├── .gitattributes ├── .gitignore ├── CStandards.md ├── GitRepoStep.zig ├── PosixStandards.md ├── ProcessFileStep.zig ├── README.md ├── awkbuild.zig ├── build.zig ├── busybox ├── build.zig └── busybox_1_35_0.config ├── capi.txt ├── filecheck.zig ├── gnumakebuild.zig ├── inc ├── alloca │ └── alloca.h ├── gnu │ ├── argp.h │ ├── getopt.h │ └── glob.h ├── libc │ ├── assert.h │ ├── ctype.h │ ├── errno.h │ ├── float.h │ ├── inttypes.h │ ├── limits.h │ ├── locale.h │ ├── math.h │ ├── private │ │ ├── README.md │ │ ├── _zig_isize.h │ │ ├── int16_t.h │ │ ├── int32_t.h │ │ ├── int64_t.h │ │ ├── int8_t.h │ │ ├── limits_and_float_shared.h │ │ ├── noreturn.h │ │ ├── null.h │ │ ├── restrict.h │ │ ├── size_t.h │ │ ├── time_t.h │ │ ├── timespec.h │ │ ├── uint16_t.h │ │ ├── uint32_t.h │ │ ├── uint64_t.h │ │ ├── uint8_t.h │ │ ├── valist.h │ │ └── wchar_t.h │ ├── setjmp.h │ ├── signal.h │ ├── stdarg.h │ ├── stddef.h │ ├── stdint.h │ ├── stdio.h │ ├── stdlib.h │ ├── string.h │ └── time.h ├── linux │ ├── alloca.h │ ├── elf.h │ ├── endian.h │ └── values.h ├── posix │ ├── ar.h │ ├── arpa │ │ └── inet.h │ ├── dirent.h │ ├── fcntl.h │ ├── inttypes.h │ ├── libgen.h │ ├── locale.h │ ├── netdb.h │ ├── netinet │ │ ├── in.h │ │ └── tcp.h │ ├── paths.h │ ├── private │ │ ├── blkcnt_t.h │ │ ├── blksize_t.h │ │ ├── dev_t.h │ │ ├── fd_set.h │ │ ├── getopt.h │ │ ├── gid_t.h │ │ ├── in_addr_t.h │ │ ├── ino_t.h │ │ ├── ipc_perm.h │ │ ├── key_t.h │ │ ├── locale_t.h │ │ ├── mode_t.h │ │ ├── nlink_t.h │ │ ├── off_t.h │ │ ├── pid_t.h │ │ ├── sa_family_t.h │ │ ├── sigset_t.h │ │ ├── sockaddr.h │ │ ├── socklen_t.h │ │ ├── ssize_t.h │ │ ├── suseconds_t.h │ │ ├── timeval.h │ │ └── uid_t.h │ ├── pthread.h │ ├── strings.h │ ├── sys │ │ ├── ioctl.h │ │ ├── ipc.h │ │ ├── param.h │ │ ├── resource.h │ │ ├── select.h │ │ ├── shm.h │ │ ├── socket.h │ │ ├── stat.h │ │ ├── time.h │ │ ├── types.h │ │ ├── uio.h │ │ └── un.h │ ├── termios.h │ └── unistd.h └── win32 │ ├── basetcsd.h │ ├── errhandlingapi.h │ ├── io.h │ ├── libloaderapi.h │ ├── private │ └── types.h │ ├── winbase.h │ ├── windef.h │ ├── windows.h │ └── winnt.h ├── luabuild.zig ├── ncurses ├── DEFS ├── build.zig └── gen-curses-h ├── src ├── cstd.zig ├── genheaders.zig ├── glibcstart.zig ├── gnu.zig ├── lib.zig ├── linux.zig ├── linux │ └── jmp.s ├── posix.c ├── posix.zig ├── printf.c ├── scanf.c ├── start.zig └── trace.zig ├── test ├── expect.c ├── expect.h ├── format.c ├── fs.c ├── getopt.c ├── hello.c ├── jmp.c ├── scanf.c ├── strings.c ├── strto.c ├── testenv.zig └── types.c └── ziglibcbuild.zig /.gitattributes: -------------------------------------------------------------------------------- 1 | *.zig text eol=lf 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | zig-cache/ 2 | zig-out/ 3 | /dep/ 4 | -------------------------------------------------------------------------------- /CStandards.md: -------------------------------------------------------------------------------- 1 | # C Standards 2 | 3 | See https://en.wikipedia.org/wiki/ANSI_C 4 | 5 | ### Timeline 6 | 7 | * 1985: ANSI releases first draft of Standard (aka C85) 8 | * 1986: ANSI releases second draft of Standard (aka C86) 9 | * 1988: ANSI publishes prerelease Standard (aka C88) 10 | * 1989: ANSI completes and ratifies the standard "X3.159-1989" "Programming Language C". 11 | This version is also known as "ANSI C" or "C89". 12 | * 1990: ISO ratifies "ANSI C" as "ISO/IEC 9899:1990" with some formatting changes. 13 | This version is also known as "C90", which makes "C89" and "C90" essentially the same language. 14 | * 1995: ISO publishes an extension to C90 called "Amendment 1" with "ISO/IEC 9899:1990/AMD1:1995". 15 | This version is also known as "C95". 16 | * 1999: ISO and ANSI adopt "ISO/IEC 9899:1999". 17 | This version is also known as "C99". 18 | * 2011: C11 ratified 19 | * 2018: C17 20 | 21 | ### C89 (aka C90) 22 | 23 | https://port70.net/~nsz/c/c89/c89-draft.html 24 | 25 | ### C95 26 | 27 | * improved multi-byte and wide character support, introduces `` and `` and multi-byte IO 28 | * adds digraphs 29 | * standard macros for alternative specification operators (e.g. `and` for `&&`) 30 | * adds `__STDC_VERSION__` macro 31 | 32 | Preprocessor test for c95: 33 | ```c 34 | #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199409L 35 | /* C95 compatible source code. */ 36 | #elif defined(__STDC__) 37 | /* C89 compatible source code. */ 38 | #endif 39 | ``` 40 | 41 | ### C99 42 | 43 | https://port70.net/~nsz/c/c99/n1256.html 44 | 45 | * new builtin types `long long`, `_Bool`, `_Complex` and `_Imaginary` 46 | * static array indices 47 | * designated initializers 48 | * compound literals 49 | * variable-length arrays 50 | * flexible array members 51 | * variadic macros 52 | * the `restrict` keyword 53 | * adds `stdint.h`, `tgmath.h`, `fenv.h` and `complex.h` 54 | * inline functions 55 | * single-line comments `//` 56 | * ability to mix declarations and code 57 | * universal character names in identifiers 58 | * removed several dangerous C89 language features like implicit function declarations and implicit `int` 59 | 60 | ### C11 61 | 62 | https://port70.net/~nsz/c/c11/n1570.html 63 | 64 | * improved unicode support 65 | * type-generic expressions using the new `_Generic` keyword 66 | * cross-platform multi-threading API `threads.h` 67 | * atomic types support in langauge and library in `stdatomic.h` 68 | 69 | ### C17 70 | 71 | * addresses defects in C11 without adding new features 72 | -------------------------------------------------------------------------------- /GitRepoStep.zig: -------------------------------------------------------------------------------- 1 | //! Publish Date: 2023_03_19 2 | //! This file is hosted at github.com/marler8997/zig-build-repos and is meant to be copied 3 | //! to projects that use it. 4 | const std = @import("std"); 5 | const GitRepoStep = @This(); 6 | 7 | pub const ShaCheck = enum { 8 | none, 9 | warn, 10 | err, 11 | 12 | pub fn reportFail(self: ShaCheck, comptime fmt: []const u8, args: anytype) void { 13 | switch (self) { 14 | .none => unreachable, 15 | .warn => std.log.warn(fmt, args), 16 | .err => { 17 | std.log.err(fmt, args); 18 | std.os.exit(0xff); 19 | }, 20 | } 21 | } 22 | }; 23 | 24 | step: std.build.Step, 25 | url: []const u8, 26 | name: []const u8, 27 | branch: ?[]const u8 = null, 28 | sha: []const u8, 29 | path: []const u8, 30 | sha_check: ShaCheck = .warn, 31 | fetch_enabled: bool, 32 | 33 | var cached_default_fetch_option: ?bool = null; 34 | pub fn defaultFetchOption(b: *std.build.Builder) bool { 35 | if (cached_default_fetch_option) |_| {} else { 36 | cached_default_fetch_option = if (b.option(bool, "fetch", "automatically fetch network resources")) |o| o else false; 37 | } 38 | return cached_default_fetch_option.?; 39 | } 40 | 41 | pub fn create(b: *std.build.Builder, opt: struct { 42 | url: []const u8, 43 | branch: ?[]const u8 = null, 44 | sha: []const u8, 45 | path: ?[]const u8 = null, 46 | sha_check: ShaCheck = .warn, 47 | fetch_enabled: ?bool = null, 48 | first_ret_addr: ?usize = null, 49 | }) *GitRepoStep { 50 | var result = b.allocator.create(GitRepoStep) catch @panic("memory"); 51 | const name = std.fs.path.basename(opt.url); 52 | result.* = GitRepoStep{ 53 | .step = std.build.Step.init(.{ 54 | .id = .custom, 55 | .name = b.fmt("clone git repository '{s}'", .{name}), 56 | .owner = b, 57 | .makeFn = make, 58 | .first_ret_addr = opt.first_ret_addr orelse @returnAddress(), 59 | .max_rss = 0, 60 | }), 61 | .url = opt.url, 62 | .name = name, 63 | .branch = opt.branch, 64 | .sha = opt.sha, 65 | .path = if (opt.path) |p| b.allocator.dupe(u8, p) catch @panic("OOM") else b.pathFromRoot(b.pathJoin(&.{ "dep", name })), 66 | .sha_check = opt.sha_check, 67 | .fetch_enabled = if (opt.fetch_enabled) |fe| fe else defaultFetchOption(b), 68 | }; 69 | return result; 70 | } 71 | 72 | // TODO: this should be included in std.build, it helps find bugs in build files 73 | fn hasDependency(step: *const std.build.Step, dep_candidate: *const std.build.Step) bool { 74 | for (step.dependencies.items) |dep| { 75 | // TODO: should probably use step.loop_flag to prevent infinite recursion 76 | // when a circular reference is encountered, or maybe keep track of 77 | // the steps encounterd with a hash set 78 | if (dep == dep_candidate or hasDependency(dep, dep_candidate)) 79 | return true; 80 | } 81 | return false; 82 | } 83 | 84 | fn make(step: *std.Build.Step, prog_node: *std.Progress.Node) !void { 85 | _ = prog_node; 86 | const self = @fieldParentPtr(GitRepoStep, "step", step); 87 | 88 | std.fs.accessAbsolute(self.path, .{}) catch { 89 | const branch_args = if (self.branch) |b| &[2][]const u8{ " -b ", b } else &[2][]const u8{ "", "" }; 90 | if (!self.fetch_enabled) { 91 | std.debug.print("Error: git repository '{s}' does not exist\n", .{self.path}); 92 | std.debug.print(" Use -Dfetch to download it automatically, or run the following to clone it:\n", .{}); 93 | std.debug.print(" git clone {s}{s}{s} {s} && git -C {3s} checkout {s} -b fordep\n", .{ 94 | self.url, 95 | branch_args[0], 96 | branch_args[1], 97 | self.path, 98 | self.sha, 99 | }); 100 | std.os.exit(1); 101 | } 102 | 103 | { 104 | var args = std.ArrayList([]const u8).init(self.step.owner.allocator); 105 | defer args.deinit(); 106 | try args.append("git"); 107 | try args.append("clone"); 108 | try args.append(self.url); 109 | // TODO: clone it to a temporary location in case of failure 110 | // also, remove that temporary location before running 111 | try args.append(self.path); 112 | if (self.branch) |branch| { 113 | try args.append("-b"); 114 | try args.append(branch); 115 | } 116 | try run(self.step.owner, args.items); 117 | } 118 | try run(self.step.owner, &[_][]const u8{ 119 | "git", 120 | "-C", 121 | self.path, 122 | "checkout", 123 | self.sha, 124 | "-b", 125 | "fordep", 126 | }); 127 | }; 128 | 129 | try self.checkSha(); 130 | } 131 | 132 | fn checkSha(self: GitRepoStep) !void { 133 | if (self.sha_check == .none) 134 | return; 135 | 136 | const result: union(enum) { failed: anyerror, output: []const u8 } = blk: { 137 | const result = std.ChildProcess.exec(.{ 138 | .allocator = self.step.owner.allocator, 139 | .argv = &[_][]const u8{ 140 | "git", 141 | "-C", 142 | self.path, 143 | "rev-parse", 144 | "HEAD", 145 | }, 146 | .cwd = self.step.owner.build_root.path, 147 | .env_map = self.step.owner.env_map, 148 | }) catch |e| break :blk .{ .failed = e }; 149 | try std.io.getStdErr().writer().writeAll(result.stderr); 150 | switch (result.term) { 151 | .Exited => |code| { 152 | if (code == 0) break :blk .{ .output = result.stdout }; 153 | break :blk .{ .failed = error.GitProcessNonZeroExit }; 154 | }, 155 | .Signal => break :blk .{ .failed = error.GitProcessFailedWithSignal }, 156 | .Stopped => break :blk .{ .failed = error.GitProcessWasStopped }, 157 | .Unknown => break :blk .{ .failed = error.GitProcessFailed }, 158 | } 159 | }; 160 | switch (result) { 161 | .failed => |err| { 162 | return self.sha_check.reportFail("failed to retreive sha for repository '{s}': {s}", .{ self.name, @errorName(err) }); 163 | }, 164 | .output => |output| { 165 | if (!std.mem.eql(u8, std.mem.trimRight(u8, output, "\n\r"), self.sha)) { 166 | return self.sha_check.reportFail("repository '{s}' sha does not match\nexpected: {s}\nactual : {s}\n", .{ self.name, self.sha, output }); 167 | } 168 | }, 169 | } 170 | } 171 | 172 | fn run(builder: *std.build.Builder, argv: []const []const u8) !void { 173 | { 174 | var msg = std.ArrayList(u8).init(builder.allocator); 175 | defer msg.deinit(); 176 | const writer = msg.writer(); 177 | var prefix: []const u8 = ""; 178 | for (argv) |arg| { 179 | try writer.print("{s}\"{s}\"", .{ prefix, arg }); 180 | prefix = " "; 181 | } 182 | std.log.info("[RUN] {s}", .{msg.items}); 183 | } 184 | 185 | var child = std.ChildProcess.init(argv, builder.allocator); 186 | child.stdin_behavior = .Ignore; 187 | child.stdout_behavior = .Inherit; 188 | child.stderr_behavior = .Inherit; 189 | child.cwd = builder.build_root.path; 190 | child.env_map = builder.env_map; 191 | 192 | try child.spawn(); 193 | const result = try child.wait(); 194 | switch (result) { 195 | .Exited => |code| if (code != 0) { 196 | std.log.err("git clone failed with exit code {}", .{code}); 197 | std.os.exit(0xff); 198 | }, 199 | else => { 200 | std.log.err("git clone failed with: {}", .{result}); 201 | std.os.exit(0xff); 202 | }, 203 | } 204 | } 205 | 206 | // Get's the repository path and also verifies that the step requesting the path 207 | // is dependent on this step. 208 | pub fn getPath(self: *const GitRepoStep, who_wants_to_know: *const std.build.Step) []const u8 { 209 | if (!hasDependency(who_wants_to_know, &self.step)) 210 | @panic("a step called GitRepoStep.getPath but has not added it as a dependency"); 211 | return self.path; 212 | } 213 | -------------------------------------------------------------------------------- /PosixStandards.md: -------------------------------------------------------------------------------- 1 | # Posix Standards 2 | 3 | See https://en.wikipedia.org/wiki/POSIX 4 | 5 | ## Before 1997 6 | 7 | POSIX was made up of the following standards: 8 | 9 | ### POSIX.1: Core Services (IEEE Std 1003.1-1988) 10 | 11 | * Incorporates ANSI C (aka C89, C90) 12 | * Process Creation/Control 13 | * Signals (floating point exceptions, segmentation/memory violations, illegal instructions, etc) 14 | * File and Directory Operations 15 | * Pipes 16 | * C Library (Standard C) 17 | * I/O Port Interface and Control 18 | * Process Triggers 19 | 20 | ### POSIX.1b: Real-time extensions (IEEE Std 1003.1b-1993, later appearing as librtthe Realtime Extensions library) 21 | 22 | * Priority Scheduling 23 | * Real-Time Signals 24 | * Clocks and Timers 25 | * Semaphores 26 | * Message Passing 27 | * Shared Memory 28 | * Async/Sync IO 29 | * Memory Locking 30 | 31 | ### POSIX.1c (IEEE Std 1003.1c-1995) 32 | 33 | * Thread Creation, Control and Cleanup 34 | * Thread Scheduling 35 | * Thread Synchronization 36 | * Signal Handling 37 | 38 | ### POSIX.2: Shell and Utilities (IEEE Std 1003.2-1992) 39 | 40 | * Command Interpreter 41 | * Utility Programs 42 | 43 | ## After 1997 44 | 45 | * POSIX.1-2001 (IEEE Std 1003.1-2001 or "Single UNIX Specification version 3") 46 | * POSIX.1-2008 (IEEE Std 1003.1-2008, 2016 Edition) 47 | * POSIX.1-2017 (IEEE Std 1003.1-2017) 48 | -------------------------------------------------------------------------------- /ProcessFileStep.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const ProcessFileStep = @This(); 3 | const filecheck = @import("filecheck.zig"); 4 | 5 | step: std.build.Step, 6 | //builder: *std.build.Builder, 7 | in_filename: []const u8, 8 | out_filename: []const u8, 9 | subs: []const Sub, 10 | 11 | pub const Sub = struct { 12 | current: []const u8, 13 | new: []const u8, 14 | }; 15 | 16 | pub fn create(b: *std.build.Builder, opt: struct { 17 | in_filename: []const u8, 18 | out_filename: []const u8, 19 | subs: []const Sub = &[_]Sub{}, 20 | }) *ProcessFileStep { 21 | var result = b.allocator.create(ProcessFileStep) catch unreachable; 22 | const name = std.fmt.allocPrint(b.allocator, "process file '{s}'", .{std.fs.path.basename(opt.in_filename)}) catch unreachable; 23 | result.* = ProcessFileStep{ 24 | .step = std.build.Step.init(.{ 25 | .id = .custom, 26 | .name = name, 27 | .owner = b, 28 | .makeFn = make, 29 | }), 30 | .in_filename = opt.in_filename, 31 | .out_filename = opt.out_filename, 32 | .subs = opt.subs, 33 | }; 34 | return result; 35 | } 36 | 37 | fn make(step: *std.build.Step, progress: *std.Progress.Node) !void { 38 | _ = progress; 39 | const self = @fieldParentPtr(ProcessFileStep, "step", step); 40 | 41 | if (try filecheck.leftFileIsNewer(self.out_filename, self.in_filename)) { 42 | return; 43 | } 44 | 45 | var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); 46 | defer arena.deinit(); 47 | const content = std.fs.cwd().readFileAlloc(arena.allocator(), self.in_filename, std.math.maxInt(usize)) catch |err| { 48 | std.log.err("failed to read file '{s}' to process ({s})", .{ self.in_filename, @errorName(err) }); 49 | std.os.exit(0xff); 50 | }; 51 | const tmp_filename = try std.fmt.allocPrint(arena.allocator(), "{s}.processing", .{self.out_filename}); 52 | { 53 | var out_file = try std.fs.cwd().createFile(tmp_filename, .{}); 54 | defer out_file.close(); 55 | try process(self.subs, out_file.writer(), content); 56 | } 57 | try std.fs.cwd().rename(tmp_filename, self.out_filename); 58 | } 59 | 60 | fn process(subs: []const Sub, writer: anytype, content: []const u8) !void { 61 | var last_flush: usize = 0; 62 | var i: usize = 0; 63 | 64 | while (i < content.len) { 65 | const rest = content[i..]; 66 | 67 | const match: ?Sub = blk: { 68 | for (subs) |sub| { 69 | if (std.mem.startsWith(u8, rest, sub.current)) { 70 | break :blk sub; 71 | } 72 | } 73 | break :blk null; 74 | }; 75 | 76 | if (match) |sub| { 77 | if (last_flush < i) try writer.writeAll(content[last_flush..i]); 78 | try writer.writeAll(sub.new); 79 | last_flush = i + sub.current.len; 80 | i = last_flush; 81 | } else { 82 | i += 1; 83 | } 84 | } 85 | 86 | if (last_flush < content.len) { 87 | try writer.writeAll(content[last_flush..]); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ziglibc 2 | 3 | An exploration on creating a libc implementation in Zig. 4 | 5 | "libc" includes implementations for the C Standard and the Posix Standard. 6 | 7 | # How to Use 8 | 9 | This is a little ugly and should change but I'm documenting it here for the adventurous. 10 | 11 | You can use ziglibc by running `zig build` on this repository. Then add these arguments 12 | to your `zig cc` command line: 13 | 14 | ``` 15 | zig cc \ 16 | -nostdlib \ 17 | -I PATH_TO_ZIGLIBC_SRC/inc/libc \ 18 | -I PATH_TO_ZIGLIBC_SRC/inc/posix \ 19 | -I PATH_TO_ZIGLIBC_SRC/inc/linux \ 20 | -L PATH_TO_ZIGLIBC_INSTALL/lib \ 21 | -lstart \ 22 | -lc 23 | ``` 24 | 25 | Currently builds with zig version `0.11.0-dev.3886+0c1bfe271`. 26 | 27 | # Thoughts 28 | 29 | I'd like a common codebase that can create libc headers that emulate various libc implementations. 30 | For this I'd like to create a database for the libc API that includes information about features, 31 | versions, behavior changes, etc. From this database, headers can be generated for any combination 32 | of parameters based on the database. 33 | 34 | I'd also like to support static and dynamic linking. Static linking means providing a full 35 | implementation for all of libc and dynamic means emulating whatever libc target the project needs. 36 | 37 | # Test Projects 38 | 39 | The following is a list of C projects that I could use to test ziglibc with: 40 | 41 | * libc-test: https://wiki.musl-libc.org/libc-test.html (use to test our libc) 42 | * Lua 43 | * sqlite 44 | * zlib 45 | * Make/Autotools 46 | * BASH 47 | * SDL 48 | * GTK 49 | * raylib 50 | * my morec project, tools directory 51 | * c4 52 | * busybox/sed 53 | * m4 preprocessor 54 | * ncurses 55 | * games in ncurses? 56 | * https://github.com/superjer/tinyc.games 57 | -------------------------------------------------------------------------------- /awkbuild.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const GitRepoStep = @import("GitRepoStep.zig"); 3 | 4 | pub fn addAwk( 5 | b: *std.build.Builder, 6 | target: anytype, 7 | optimize: anytype, 8 | libc_only_std_static: *std.build.LibExeObjStep, 9 | zig_start: *std.build.LibExeObjStep, 10 | zig_posix: *std.build.LibExeObjStep, 11 | ) *std.build.LibExeObjStep { 12 | const repo = GitRepoStep.create(b, .{ 13 | .url = "https://github.com/onetrueawk/awk", 14 | .sha = "9e248c317b88470fc86aa7c988919dc49452c88c", 15 | .branch = null, 16 | }); 17 | 18 | // const config_step = b.addWriteFile( 19 | // b.pathJoin(&.{repo.path, "src", "config.h"}), 20 | // "#define VERSION \"1.0\"", 21 | // ); 22 | // config_step.step.dependOn(&repo.step); 23 | 24 | const exe = b.addExecutable(.{ 25 | .name = "awk", 26 | .target = target, 27 | .optimize = optimize, 28 | }); 29 | const install = b.addInstallArtifact(exe, .{}); 30 | exe.step.dependOn(&repo.step); 31 | // exe.step.dependOn(&config_step.step); 32 | const repo_path = repo.getPath(&exe.step); 33 | var files = std.ArrayList([]const u8).init(b.allocator); 34 | const sources = [_][]const u8{ 35 | // "main.c", "cmph.c", "hash.c", "chm.c", "bmz.c", "bmz8.c", "brz.c", "fch.c", 36 | // "bdz.c", "bdz_ph.c", "chd_ph.c", "chd.c", "jenkins_hash.c", "graph.c", "vqueue.c", 37 | // "buffer_manager.c", "fch_buckets.c", "miller_rabin.c", "compressed_seq.c", 38 | // "compressed_rank.c", "buffer_entry.c", "select.c", "cmph_structs.c", 39 | }; 40 | for (sources) |src| { 41 | files.append(b.pathJoin(&.{ repo_path, "src", src })) catch unreachable; 42 | } 43 | 44 | exe.addCSourceFiles(files.toOwnedSlice() catch unreachable, &[_][]const u8{ 45 | "-std=c11", 46 | }); 47 | 48 | exe.addIncludePath(.{ .path = "inc/libc" }); 49 | exe.addIncludePath(.{ .path = "inc/posix" }); 50 | exe.addIncludePath(.{ .path = "inc/gnu" }); 51 | exe.linkLibrary(libc_only_std_static); 52 | exe.linkLibrary(zig_start); 53 | exe.linkLibrary(zig_posix); 54 | // TODO: should libc_only_std_static and zig_start be able to add library dependencies? 55 | if (target.getOs().tag == .windows) { 56 | exe.linkSystemLibrary("ntdll"); 57 | exe.linkSystemLibrary("kernel32"); 58 | } 59 | 60 | const step = b.step("awk", "build awk"); 61 | step.dependOn(&install.step); 62 | 63 | return exe; 64 | } 65 | -------------------------------------------------------------------------------- /build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const GitRepoStep = @import("GitRepoStep.zig"); 3 | const libcbuild = @import("ziglibcbuild.zig"); 4 | const luabuild = @import("luabuild.zig"); 5 | const awkbuild = @import("awkbuild.zig"); 6 | const gnumakebuild = @import("gnumakebuild.zig"); 7 | 8 | pub fn build(b: *std.build.Builder) void { 9 | const trace_enabled = b.option(bool, "trace", "enable libc tracing") orelse false; 10 | 11 | { 12 | const exe = b.addExecutable(.{ 13 | .name = "genheaders", 14 | .root_source_file = .{ .path = "src" ++ std.fs.path.sep_str ++ "genheaders.zig" }, 15 | }); 16 | const run = b.addRunArtifact(exe); 17 | run.addArg(b.pathFromRoot("capi.txt")); 18 | b.step("genheaders", "Generate C Headers").dependOn(&run.step); 19 | } 20 | 21 | const target = b.standardTargetOptions(.{}); 22 | const optimize = b.standardOptimizeOption(.{}); 23 | 24 | const zig_start = libcbuild.addZigStart(b, target, optimize); 25 | b.step("start", "").dependOn(&installArtifact(b, zig_start).step); 26 | 27 | const libc_full_static = libcbuild.addLibc(b, .{ 28 | .variant = .full, 29 | .link = .static, 30 | .start = .ziglibc, 31 | .trace = trace_enabled, 32 | .target = target, 33 | .optimize = optimize, 34 | }); 35 | b.installArtifact(libc_full_static); 36 | const libc_full_shared = libcbuild.addLibc(b, .{ 37 | .variant = .full, 38 | .link = .shared, 39 | .start = .ziglibc, 40 | .trace = trace_enabled, 41 | .target = target, 42 | .optimize = optimize, 43 | }); 44 | b.step("libc-full-shared", "").dependOn(&installArtifact(b, libc_full_shared).step); 45 | // TODO: create a specs file? 46 | // you can add -specs=file to the gcc command line to override values in the spec 47 | 48 | const libc_only_std_static = libcbuild.addLibc(b, .{ 49 | .variant = .only_std, 50 | .link = .static, 51 | .start = .ziglibc, 52 | .trace = trace_enabled, 53 | .target = target, 54 | .optimize = optimize, 55 | }); 56 | b.installArtifact(libc_only_std_static); 57 | const libc_only_std_shared = libcbuild.addLibc(b, .{ 58 | .variant = .only_std, 59 | .link = .shared, 60 | .start = .ziglibc, 61 | .trace = trace_enabled, 62 | .target = target, 63 | .optimize = optimize, 64 | }); 65 | b.installArtifact(libc_only_std_shared); 66 | 67 | const libc_only_posix = libcbuild.addLibc(b, .{ 68 | .variant = .only_posix, 69 | .link = .static, 70 | .start = .ziglibc, 71 | .trace = trace_enabled, 72 | .target = target, 73 | .optimize = optimize, 74 | }); 75 | b.installArtifact(libc_only_posix); 76 | 77 | const libc_only_linux = libcbuild.addLibc(b, .{ 78 | .variant = .only_linux, 79 | .link = .static, 80 | .start = .ziglibc, 81 | .trace = trace_enabled, 82 | .target = target, 83 | .optimize = optimize, 84 | }); 85 | b.installArtifact(libc_only_linux); 86 | 87 | const libc_only_gnu = libcbuild.addLibc(b, .{ 88 | .variant = .only_gnu, 89 | .link = .static, 90 | .start = .ziglibc, 91 | .trace = trace_enabled, 92 | .target = target, 93 | .optimize = optimize, 94 | }); 95 | b.installArtifact(libc_only_gnu); 96 | 97 | const test_step = b.step("test", "Run unit tests"); 98 | 99 | const test_env_exe = b.addExecutable(.{ 100 | .name = "testenv", 101 | .root_source_file = .{ .path = "test" ++ std.fs.path.sep_str ++ "testenv.zig" }, 102 | .target = target, 103 | .optimize = optimize, 104 | }); 105 | 106 | { 107 | const exe = addTest("hello", b, target, optimize, libc_only_std_static, zig_start); 108 | const run_step = b.addRunArtifact(exe); 109 | run_step.addCheck(.{ .expect_stdout_exact = "Hello\n" }); 110 | test_step.dependOn(&run_step.step); 111 | } 112 | { 113 | const exe = addTest("strings", b, target, optimize, libc_only_std_static, zig_start); 114 | const run_step = b.addRunArtifact(exe); 115 | run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" }); 116 | test_step.dependOn(&run_step.step); 117 | } 118 | { 119 | const exe = addTest("fs", b, target, optimize, libc_only_std_static, zig_start); 120 | const run_step = b.addRunArtifact(test_env_exe); 121 | run_step.addArtifactArg(exe); 122 | run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" }); 123 | test_step.dependOn(&run_step.step); 124 | } 125 | { 126 | const exe = addTest("format", b, target, optimize, libc_only_std_static, zig_start); 127 | const run_step = b.addRunArtifact(test_env_exe); 128 | run_step.addArtifactArg(exe); 129 | run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" }); 130 | test_step.dependOn(&run_step.step); 131 | } 132 | { 133 | const exe = addTest("types", b, target, optimize, libc_only_std_static, zig_start); 134 | const run_step = b.addRunArtifact(exe); 135 | run_step.addArg(b.fmt("{}", .{@divExact(target.toTarget().ptrBitWidth(), 8)})); 136 | run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" }); 137 | test_step.dependOn(&run_step.step); 138 | } 139 | { 140 | const exe = addTest("scanf", b, target, optimize, libc_only_std_static, zig_start); 141 | const run_step = b.addRunArtifact(exe); 142 | run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" }); 143 | test_step.dependOn(&run_step.step); 144 | } 145 | { 146 | const exe = addTest("strto", b, target, optimize, libc_only_std_static, zig_start); 147 | const run_step = b.addRunArtifact(exe); 148 | run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" }); 149 | test_step.dependOn(&run_step.step); 150 | } 151 | { 152 | const exe = addTest("getopt", b, target, optimize, libc_only_std_static, zig_start); 153 | addPosix(exe, libc_only_posix); 154 | { 155 | const run = b.addRunArtifact(exe); 156 | run.addCheck(.{ .expect_stdout_exact = "aflag=0, c_arg='(null)'\n" }); 157 | test_step.dependOn(&run.step); 158 | } 159 | { 160 | const run = b.addRunArtifact(exe); 161 | run.addArgs(&.{"-a"}); 162 | run.addCheck(.{ .expect_stdout_exact = "aflag=1, c_arg='(null)'\n" }); 163 | test_step.dependOn(&run.step); 164 | } 165 | { 166 | const run = b.addRunArtifact(exe); 167 | run.addArgs(&.{ "-c", "hello" }); 168 | run.addCheck(.{ .expect_stdout_exact = "aflag=0, c_arg='hello'\n" }); 169 | test_step.dependOn(&run.step); 170 | } 171 | } 172 | 173 | // this test only works on linux right now 174 | if (target.getOsTag() == .linux) { 175 | const exe = addTest("jmp", b, target, optimize, libc_only_std_static, zig_start); 176 | const run_step = b.addRunArtifact(exe); 177 | run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" }); 178 | test_step.dependOn(&run_step.step); 179 | } 180 | 181 | addLibcTest(b, target, optimize, libc_only_std_static, zig_start, libc_only_posix); 182 | addTinyRegexCTests(b, target, optimize, libc_only_std_static, zig_start, libc_only_posix); 183 | _ = addLua(b, target, optimize, libc_only_std_static, libc_only_posix, zig_start); 184 | _ = addCmph(b, target, optimize, libc_only_std_static, zig_start, libc_only_posix); 185 | _ = addYacc(b, target, optimize, libc_only_std_static, zig_start, libc_only_posix); 186 | _ = addYabfc(b, target, optimize, libc_only_std_static, zig_start, libc_only_posix, libc_only_gnu); 187 | _ = addSecretGame(b, target, optimize, libc_only_std_static, zig_start, libc_only_posix, libc_only_gnu); 188 | _ = awkbuild.addAwk(b, target, optimize, libc_only_std_static, libc_only_posix, zig_start); 189 | _ = gnumakebuild.addGnuMake(b, target, optimize, libc_only_std_static, libc_only_posix, zig_start); 190 | 191 | _ = @import("busybox/build.zig").add(b, target, optimize, libc_only_std_static, libc_only_posix); 192 | _ = @import("ncurses/build.zig").add(b, target, optimize, libc_only_std_static, libc_only_posix); 193 | } 194 | 195 | // re-implements Build.installArtifact but also returns it 196 | fn installArtifact(b: *std.Build, artifact: anytype) *std.Build.Step.InstallArtifact { 197 | const install = b.addInstallArtifact(artifact, .{}); 198 | b.getInstallStep().dependOn(&install.step); 199 | return install; 200 | } 201 | 202 | fn addPosix(artifact: *std.build.LibExeObjStep, zig_posix: *std.build.LibExeObjStep) void { 203 | artifact.linkLibrary(zig_posix); 204 | artifact.addIncludePath(.{ .path = "inc" ++ std.fs.path.sep_str ++ "posix" }); 205 | } 206 | 207 | fn addTest( 208 | comptime name: []const u8, 209 | b: *std.build.Builder, 210 | target: anytype, 211 | optimize: anytype, 212 | libc_only_std_static: *std.build.LibExeObjStep, 213 | zig_start: *std.build.LibExeObjStep, 214 | ) *std.build.LibExeObjStep { 215 | const exe = b.addExecutable(.{ 216 | .name = name, 217 | .root_source_file = .{ .path = "test" ++ std.fs.path.sep_str ++ name ++ ".c" }, 218 | .target = target, 219 | .optimize = optimize, 220 | }); 221 | exe.addCSourceFiles(&.{"test" ++ std.fs.path.sep_str ++ "expect.c"}, &[_][]const u8{}); 222 | exe.addIncludePath(.{ .path = "inc" ++ std.fs.path.sep_str ++ "libc" }); 223 | exe.addIncludePath(.{ .path = "inc" ++ std.fs.path.sep_str ++ "posix" }); 224 | exe.linkLibrary(libc_only_std_static); 225 | exe.linkLibrary(zig_start); 226 | // TODO: should libc_only_std_static and zig_start be able to add library dependencies? 227 | if (target.getOs().tag == .windows) { 228 | exe.linkSystemLibrary("ntdll"); 229 | exe.linkSystemLibrary("kernel32"); 230 | } 231 | return exe; 232 | } 233 | 234 | fn addLibcTest( 235 | b: *std.build.Builder, 236 | target: anytype, 237 | optimize: anytype, 238 | libc_only_std_static: *std.build.LibExeObjStep, 239 | zig_start: *std.build.LibExeObjStep, 240 | libc_only_posix: *std.build.LibExeObjStep, 241 | ) void { 242 | const libc_test_repo = GitRepoStep.create(b, .{ 243 | .url = "git://nsz.repo.hu:49100/repo/libc-test", 244 | .sha = "b7ec467969a53756258778fa7d9b045f912d1c93", 245 | .branch = null, 246 | .fetch_enabled = true, 247 | }); 248 | const libc_test_path = libc_test_repo.path; 249 | const libc_test_step = b.step("libc-test", "run tests from the libc-test project"); 250 | 251 | // inttypes 252 | inline for (.{ "assert", "ctype", "errno", "main", "stdbool", "stddef", "string" }) |name| { 253 | const lib = b.addObject(.{ 254 | .name = "libc-test-api-" ++ name, 255 | .root_source_file = .{ .path = b.pathJoin(&.{ libc_test_path, "src", "api", name ++ ".c" }) }, 256 | .target = target, 257 | .optimize = optimize, 258 | }); 259 | lib.addIncludePath(.{ .path = "inc" ++ std.fs.path.sep_str ++ "libc" }); 260 | lib.step.dependOn(&libc_test_repo.step); 261 | libc_test_step.dependOn(&lib.step); 262 | } 263 | const libc_inc_path = b.pathJoin(&.{ libc_test_path, "src", "common" }); 264 | const common_src = &[_][]const u8{ 265 | b.pathJoin(&.{ libc_test_path, "src", "common", "print.c" }), 266 | }; 267 | 268 | // strtol, it seems there might be some disagreement between libc-test/glibc 269 | // about how strtoul interprets negative numbers, so leaving out strtol for now 270 | inline for (.{ "argv", "basename", "clock_gettime", "string" }) |name| { 271 | const exe = b.addExecutable(.{ 272 | .name = "libc-test-functional-" ++ name, 273 | .root_source_file = .{ .path = b.pathJoin(&.{ libc_test_path, "src", "functional", name ++ ".c" }) }, 274 | .target = target, 275 | .optimize = optimize, 276 | }); 277 | exe.addCSourceFiles(common_src, &[_][]const u8{}); 278 | exe.step.dependOn(&libc_test_repo.step); 279 | exe.addIncludePath(.{ .path = libc_inc_path }); 280 | exe.addIncludePath(.{ .path = "inc" ++ std.fs.path.sep_str ++ "libc" }); 281 | exe.addIncludePath(.{ .path = "inc" ++ std.fs.path.sep_str ++ "posix" }); 282 | exe.linkLibrary(libc_only_std_static); 283 | exe.linkLibrary(zig_start); 284 | exe.linkLibrary(libc_only_posix); 285 | // TODO: should libc_only_std_static and zig_start be able to add library dependencies? 286 | if (target.getOs().tag == .windows) { 287 | exe.linkSystemLibrary("ntdll"); 288 | exe.linkSystemLibrary("kernel32"); 289 | } 290 | libc_test_step.dependOn(&b.addRunArtifact(exe).step); 291 | } 292 | } 293 | 294 | fn addTinyRegexCTests( 295 | b: *std.build.Builder, 296 | target: anytype, 297 | optimize: anytype, 298 | libc_only_std_static: *std.build.LibExeObjStep, 299 | zig_start: *std.build.LibExeObjStep, 300 | zig_posix: *std.build.LibExeObjStep, 301 | ) void { 302 | const repo = GitRepoStep.create(b, .{ 303 | .url = "https://github.com/marler8997/tiny-regex-c", 304 | .sha = "95ef2ad35d36783d789b0ade3178b30a942f085c", 305 | .branch = "nocompile", 306 | .fetch_enabled = true, 307 | }); 308 | 309 | const re_step = b.step("re-tests", "run the tiny-regex-c tests"); 310 | inline for (&[_][]const u8{ "test1", "test3" }) |test_name| { 311 | const exe = b.addExecutable(.{ 312 | .name = "re" ++ test_name, 313 | .root_source_file = null, 314 | .target = target, 315 | .optimize = optimize, 316 | }); 317 | //b.installArtifact(exe); 318 | exe.step.dependOn(&repo.step); 319 | const repo_path = repo.getPath(&exe.step); 320 | var files = std.ArrayList([]const u8).init(b.allocator); 321 | const sources = [_][]const u8{ 322 | "re.c", "tests" ++ std.fs.path.sep_str ++ test_name ++ ".c", 323 | }; 324 | for (sources) |src| { 325 | files.append(b.pathJoin(&.{ repo_path, src })) catch unreachable; 326 | } 327 | 328 | exe.addCSourceFiles(files.toOwnedSlice() catch unreachable, &[_][]const u8{ 329 | "-std=c99", 330 | }); 331 | exe.addIncludePath(.{ .path = repo_path }); 332 | 333 | exe.addIncludePath(.{ .path = "inc/libc" }); 334 | exe.addIncludePath(.{ .path = "inc/posix" }); 335 | exe.linkLibrary(libc_only_std_static); 336 | exe.linkLibrary(zig_start); 337 | exe.linkLibrary(zig_posix); 338 | // TODO: should libc_only_std_static and zig_start be able to add library dependencies? 339 | if (target.getOs().tag == .windows) { 340 | exe.linkSystemLibrary("ntdll"); 341 | exe.linkSystemLibrary("kernel32"); 342 | } 343 | 344 | //const step = b.step("re", "build the re (tiny-regex-c) tool"); 345 | //step.dependOn(&exe.install_step.?.step); 346 | const run = b.addRunArtifact(exe); 347 | re_step.dependOn(&run.step); 348 | } 349 | } 350 | 351 | fn addLua( 352 | b: *std.build.Builder, 353 | target: anytype, 354 | optimize: anytype, 355 | libc_only_std_static: *std.build.LibExeObjStep, 356 | libc_only_posix: *std.build.LibExeObjStep, 357 | zig_start: *std.build.LibExeObjStep, 358 | ) *std.build.LibExeObjStep { 359 | const lua_repo = GitRepoStep.create(b, .{ 360 | .url = "https://github.com/lua/lua", 361 | .sha = "5d708c3f9cae12820e415d4f89c9eacbe2ab964b", 362 | .branch = "v5.4.4", 363 | .fetch_enabled = true, 364 | }); 365 | const lua_exe = b.addExecutable(.{ 366 | .name = "lua", 367 | .target = target, 368 | .optimize = optimize, 369 | }); 370 | lua_exe.step.dependOn(&lua_repo.step); 371 | const install = b.addInstallArtifact(lua_exe, .{}); 372 | // doesn't compile for windows for some reason 373 | if (target.getOs().tag != .windows) { 374 | b.getInstallStep().dependOn(&install.step); 375 | } 376 | const lua_repo_path = lua_repo.getPath(&lua_exe.step); 377 | var files = std.ArrayList([]const u8).init(b.allocator); 378 | files.append(b.pathJoin(&.{ lua_repo_path, "lua.c" })) catch unreachable; 379 | inline for (luabuild.core_objects) |obj| { 380 | files.append(b.pathJoin(&.{ lua_repo_path, obj ++ ".c" })) catch unreachable; 381 | } 382 | inline for (luabuild.aux_objects) |obj| { 383 | files.append(b.pathJoin(&.{ lua_repo_path, obj ++ ".c" })) catch unreachable; 384 | } 385 | inline for (luabuild.lib_objects) |obj| { 386 | files.append(b.pathJoin(&.{ lua_repo_path, obj ++ ".c" })) catch unreachable; 387 | } 388 | 389 | lua_exe.addCSourceFiles(files.toOwnedSlice() catch unreachable, &[_][]const u8{ 390 | "-nostdinc", 391 | "-nostdlib", 392 | "-std=c99", 393 | }); 394 | 395 | lua_exe.addIncludePath(.{ .path = "inc" ++ std.fs.path.sep_str ++ "libc" }); 396 | lua_exe.linkLibrary(libc_only_std_static); 397 | lua_exe.linkLibrary(libc_only_posix); 398 | lua_exe.linkLibrary(zig_start); 399 | // TODO: should libc_only_std_static and zig_start be able to add library dependencies? 400 | if (target.getOs().tag == .windows) { 401 | lua_exe.addIncludePath(.{ .path = "inc/win32" }); 402 | lua_exe.linkSystemLibrary("ntdll"); 403 | lua_exe.linkSystemLibrary("kernel32"); 404 | } 405 | 406 | const step = b.step("lua", "build/install the LUA interpreter"); 407 | step.dependOn(&install.step); 408 | 409 | const test_step = b.step("lua-test", "Run the lua tests"); 410 | 411 | for ([_][]const u8{ "bwcoercion.lua", "tracegc.lua" }) |test_file| { 412 | var run_test = b.addRunArtifact(lua_exe); 413 | run_test.addArg(b.pathJoin(&.{ lua_repo_path, "testes", test_file })); 414 | test_step.dependOn(&run_test.step); 415 | } 416 | 417 | return lua_exe; 418 | } 419 | 420 | fn addCmph( 421 | b: *std.build.Builder, 422 | target: anytype, 423 | optimize: anytype, 424 | libc_only_std_static: *std.build.LibExeObjStep, 425 | zig_start: *std.build.LibExeObjStep, 426 | zig_posix: *std.build.LibExeObjStep, 427 | ) *std.build.LibExeObjStep { 428 | const repo = GitRepoStep.create(b, .{ 429 | //.url = "https://git.code.sf.net/p/cmph/git", 430 | .url = "https://github.com/bonitao/cmph", 431 | .sha = "abd5e1e17e4d51b3e24459ab9089dc0522846d0d", 432 | .branch = null, 433 | .fetch_enabled = true, 434 | }); 435 | 436 | const config_step = b.addWriteFile( 437 | b.pathJoin(&.{ repo.path, "src", "config.h" }), 438 | "#define VERSION \"1.0\"", 439 | ); 440 | config_step.step.dependOn(&repo.step); 441 | 442 | const exe = b.addExecutable(.{ 443 | .name = "cmph", 444 | .target = target, 445 | .optimize = optimize, 446 | }); 447 | const install = installArtifact(b, exe); 448 | exe.step.dependOn(&repo.step); 449 | exe.step.dependOn(&config_step.step); 450 | const repo_path = repo.getPath(&exe.step); 451 | var files = std.ArrayList([]const u8).init(b.allocator); 452 | const sources = [_][]const u8{ 453 | "main.c", "cmph.c", "hash.c", "chm.c", "bmz.c", "bmz8.c", "brz.c", "fch.c", 454 | "bdz.c", "bdz_ph.c", "chd_ph.c", "chd.c", "jenkins_hash.c", "graph.c", "vqueue.c", "buffer_manager.c", 455 | "fch_buckets.c", "miller_rabin.c", "compressed_seq.c", "compressed_rank.c", "buffer_entry.c", "select.c", "cmph_structs.c", 456 | }; 457 | for (sources) |src| { 458 | files.append(b.pathJoin(&.{ repo_path, "src", src })) catch unreachable; 459 | } 460 | 461 | exe.addCSourceFiles(files.toOwnedSlice() catch unreachable, &[_][]const u8{ 462 | "-std=c11", 463 | }); 464 | 465 | exe.addIncludePath(.{ .path = "inc/libc" }); 466 | exe.addIncludePath(.{ .path = "inc/posix" }); 467 | exe.addIncludePath(.{ .path = "inc/gnu" }); 468 | exe.linkLibrary(libc_only_std_static); 469 | exe.linkLibrary(zig_start); 470 | exe.linkLibrary(zig_posix); 471 | // TODO: should libc_only_std_static and zig_start be able to add library dependencies? 472 | if (target.getOs().tag == .windows) { 473 | exe.linkSystemLibrary("ntdll"); 474 | exe.linkSystemLibrary("kernel32"); 475 | } 476 | 477 | const step = b.step("cmph", "build the cmph tool"); 478 | step.dependOn(&install.step); 479 | 480 | return exe; 481 | } 482 | 483 | fn addYacc( 484 | b: *std.build.Builder, 485 | target: anytype, 486 | optimize: anytype, 487 | libc_only_std_static: *std.build.LibExeObjStep, 488 | zig_start: *std.build.LibExeObjStep, 489 | zig_posix: *std.build.LibExeObjStep, 490 | ) *std.build.LibExeObjStep { 491 | const repo = GitRepoStep.create(b, .{ 492 | .url = "https://github.com/ibara/yacc", 493 | .sha = "1a4138ce2385ec676c6d374245fda5a9cd2fbee2", 494 | .branch = null, 495 | .fetch_enabled = true, 496 | }); 497 | 498 | const config_step = b.addWriteFile(b.pathJoin(&.{ repo.path, "config.h" }), 499 | \\// for simplicity just don't supported __unused 500 | \\#define __unused 501 | \\// for simplicity we're just not supporting noreturn 502 | \\#define __dead 503 | \\//#define HAVE_PROGNAME 504 | \\//#define HAVE_ASPRINTF 505 | \\//#define HAVE_PLEDGE 506 | \\//#define HAVE_REALLOCARRAY 507 | \\#define HAVE_STRLCPY 508 | \\ 509 | ); 510 | config_step.step.dependOn(&repo.step); 511 | const gen_progname_step = b.addWriteFile(b.pathJoin(&.{ repo.path, "progname.c" }), 512 | \\// workaround __progname not defined, https://github.com/ibara/yacc/pull/1 513 | \\char *__progname; 514 | \\ 515 | ); 516 | gen_progname_step.step.dependOn(&repo.step); 517 | 518 | const exe = b.addExecutable(.{ 519 | .name = "yacc", 520 | .target = target, 521 | .optimize = optimize, 522 | }); 523 | const install = installArtifact(b, exe); 524 | exe.step.dependOn(&repo.step); 525 | exe.step.dependOn(&config_step.step); 526 | exe.step.dependOn(&gen_progname_step.step); 527 | const repo_path = repo.getPath(&exe.step); 528 | var files = std.ArrayList([]const u8).init(b.allocator); 529 | const sources = [_][]const u8{ 530 | "closure.c", "error.c", "lalr.c", "lr0.c", "main.c", "mkpar.c", "output.c", "reader.c", 531 | "skeleton.c", "symtab.c", "verbose.c", "warshall.c", "portable.c", "progname.c", 532 | }; 533 | for (sources) |src| { 534 | files.append(b.pathJoin(&.{ repo_path, src })) catch unreachable; 535 | } 536 | 537 | exe.addCSourceFiles(files.toOwnedSlice() catch unreachable, &[_][]const u8{ 538 | "-std=c90", 539 | }); 540 | 541 | exe.addIncludePath(.{ .path = "inc/libc" }); 542 | exe.addIncludePath(.{ .path = "inc/posix" }); 543 | exe.linkLibrary(libc_only_std_static); 544 | exe.linkLibrary(zig_start); 545 | exe.linkLibrary(zig_posix); 546 | // TODO: should libc_only_std_static and zig_start be able to add library dependencies? 547 | if (target.getOs().tag == .windows) { 548 | exe.linkSystemLibrary("ntdll"); 549 | exe.linkSystemLibrary("kernel32"); 550 | } 551 | 552 | const step = b.step("yacc", "build the yacc tool"); 553 | step.dependOn(&install.step); 554 | 555 | return exe; 556 | } 557 | 558 | fn addYabfc( 559 | b: *std.build.Builder, 560 | target: anytype, 561 | optimize: anytype, 562 | libc_only_std_static: *std.build.LibExeObjStep, 563 | zig_start: *std.build.LibExeObjStep, 564 | zig_posix: *std.build.LibExeObjStep, 565 | zig_gnu: *std.build.LibExeObjStep, 566 | ) *std.build.LibExeObjStep { 567 | const repo = GitRepoStep.create(b, .{ 568 | .url = "https://github.com/julianneswinoga/yabfc", 569 | .sha = "a789be25a0918d330b7a4de12db0d33e0785f244", 570 | .branch = null, 571 | .fetch_enabled = true, 572 | }); 573 | 574 | const exe = b.addExecutable(.{ 575 | .name = "yabfc", 576 | .target = target, 577 | .optimize = optimize, 578 | }); 579 | const install = installArtifact(b, exe); 580 | exe.step.dependOn(&repo.step); 581 | const repo_path = repo.getPath(&exe.step); 582 | var files = std.ArrayList([]const u8).init(b.allocator); 583 | const sources = [_][]const u8{ 584 | "assembly.c", "elfHelper.c", "helpers.c", "optimize.c", "yabfc.c", 585 | }; 586 | for (sources) |src| { 587 | files.append(b.pathJoin(&.{ repo_path, src })) catch unreachable; 588 | } 589 | exe.addCSourceFiles(files.toOwnedSlice() catch unreachable, &[_][]const u8{ 590 | "-std=c99", 591 | }); 592 | 593 | exe.addIncludePath(.{ .path = "inc/libc" }); 594 | exe.addIncludePath(.{ .path = "inc/posix" }); 595 | exe.addIncludePath(.{ .path = "inc/linux" }); 596 | exe.addIncludePath(.{ .path = "inc/gnu" }); 597 | exe.linkLibrary(libc_only_std_static); 598 | exe.linkLibrary(zig_start); 599 | exe.linkLibrary(zig_posix); 600 | exe.linkLibrary(zig_gnu); 601 | // TODO: should libc_only_std_static and zig_start be able to add library dependencies? 602 | if (target.getOs().tag == .windows) { 603 | exe.linkSystemLibrary("ntdll"); 604 | exe.linkSystemLibrary("kernel32"); 605 | } 606 | 607 | const step = b.step("yabfc", "build/install the yabfc tool (Yet Another BrainFuck Compiler)"); 608 | step.dependOn(&install.step); 609 | 610 | return exe; 611 | } 612 | 613 | fn addSecretGame( 614 | b: *std.build.Builder, 615 | target: anytype, 616 | optimize: anytype, 617 | libc_only_std_static: *std.build.LibExeObjStep, 618 | zig_start: *std.build.LibExeObjStep, 619 | zig_posix: *std.build.LibExeObjStep, 620 | zig_gnu: *std.build.LibExeObjStep, 621 | ) *std.build.LibExeObjStep { 622 | const repo = GitRepoStep.create(b, .{ 623 | .url = "https://github.com/ethinethin/Secret", 624 | .sha = "8ec8442f84f8bed2cb3985455e7af4d1ce605401", 625 | .branch = null, 626 | .fetch_enabled = true, 627 | }); 628 | 629 | const exe = b.addExecutable(.{ 630 | .name = "secret", 631 | .target = target, 632 | .optimize = optimize, 633 | }); 634 | const install = b.addInstallArtifact(exe, .{}); 635 | exe.step.dependOn(&repo.step); 636 | const repo_path = repo.getPath(&exe.step); 637 | var files = std.ArrayList([]const u8).init(b.allocator); 638 | const sources = [_][]const u8{ 639 | "main.c", "inter.c", "input.c", "items.c", "rooms.c", "linenoise/linenoise.c", 640 | }; 641 | for (sources) |src| { 642 | files.append(b.pathJoin(&.{ repo_path, src })) catch unreachable; 643 | } 644 | exe.addCSourceFiles(files.toOwnedSlice() catch unreachable, &[_][]const u8{ 645 | "-std=c90", 646 | }); 647 | 648 | exe.addIncludePath(.{ .path = "inc/libc" }); 649 | exe.addIncludePath(.{ .path = "inc/posix" }); 650 | exe.addIncludePath(.{ .path = "inc/linux" }); 651 | exe.addIncludePath(.{ .path = "inc/gnu" }); 652 | exe.linkLibrary(libc_only_std_static); 653 | exe.linkLibrary(zig_start); 654 | exe.linkLibrary(zig_posix); 655 | exe.linkLibrary(zig_gnu); 656 | // TODO: should libc_only_std_static and zig_start be able to add library dependencies? 657 | if (target.getOs().tag == .windows) { 658 | exe.linkSystemLibrary("ntdll"); 659 | exe.linkSystemLibrary("kernel32"); 660 | } 661 | 662 | const step = b.step("secret", "build/install the secret game"); 663 | step.dependOn(&install.step); 664 | 665 | return exe; 666 | } 667 | -------------------------------------------------------------------------------- /busybox/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const GitRepoStep = @import("../GitRepoStep.zig"); 3 | 4 | const BusyboxPrepStep = struct { 5 | step: std.build.Step, 6 | builder: *std.build.Builder, 7 | repo_path: []const u8, 8 | pub fn create(b: *std.build.Builder, repo: *GitRepoStep) *BusyboxPrepStep { 9 | var result = b.allocator.create(BusyboxPrepStep) catch unreachable; 10 | result.* = BusyboxPrepStep{ 11 | .step = std.build.Step.init(.{ 12 | .id = .custom, 13 | .name = "busybox prep", 14 | .owner = b, 15 | .makeFn = make, 16 | }), 17 | .builder = b, 18 | .repo_path = repo.path, 19 | }; 20 | result.*.step.dependOn(&repo.step); 21 | return result; 22 | } 23 | fn make(step: *std.build.Step, progress: *std.Progress.Node) !void { 24 | _ = progress; 25 | const self = @fieldParentPtr(BusyboxPrepStep, "step", step); 26 | const b = self.builder; 27 | 28 | std.log.warn("TODO: check config file timestamp to prevent unnecessary copy", .{}); 29 | var src_dir = try std.fs.cwd().openDir(b.pathJoin(&.{ b.build_root.path.?, "busybox" }), .{}); 30 | defer src_dir.close(); 31 | var dst_dir = try std.fs.cwd().openDir(self.repo_path, .{}); 32 | defer dst_dir.close(); 33 | try src_dir.copyFile("busybox_1_35_0.config", dst_dir, ".config", .{}); 34 | } 35 | }; 36 | 37 | pub fn add( 38 | b: *std.build.Builder, 39 | target: anytype, 40 | optimize: anytype, 41 | libc_only_std_static: *std.build.LibExeObjStep, 42 | zig_posix: *std.build.LibExeObjStep, 43 | ) *std.build.LibExeObjStep { 44 | const repo = GitRepoStep.create(b, .{ 45 | .url = "https://git.busybox.net/busybox", 46 | .sha = "e512aeb0fb3c585948ae6517cfdf4a53cf99774d", 47 | .branch = null, 48 | }); 49 | 50 | const prep = BusyboxPrepStep.create(b, repo); 51 | 52 | const exe = b.addExecutable(.{ 53 | .name = "busybox", 54 | .target = target, 55 | .optimize = optimize, 56 | }); 57 | const install = b.addInstallArtifact(exe, .{}); 58 | exe.step.dependOn(&prep.step); 59 | const repo_path = repo.getPath(&exe.step); 60 | var files = std.ArrayList([]const u8).init(b.allocator); 61 | const sources = [_][]const u8{ 62 | "editors/sed.c", 63 | }; 64 | for (sources) |src| { 65 | files.append(b.pathJoin(&.{ repo_path, src })) catch unreachable; 66 | } 67 | exe.addCSourceFiles(files.toOwnedSlice() catch unreachable, &[_][]const u8{ 68 | "-std=c99", 69 | }); 70 | exe.addIncludePath(.{ .path = b.pathJoin(&.{ repo_path, "include" }) }); 71 | 72 | exe.addIncludePath(.{ .path = "inc/libc" }); 73 | exe.addIncludePath(.{ .path = "inc/posix" }); 74 | exe.addIncludePath(.{ .path = "inc/linux" }); 75 | exe.linkLibrary(libc_only_std_static); 76 | //exe.linkLibrary(zig_start); 77 | exe.linkLibrary(zig_posix); 78 | // TODO: should libc_only_std_static and zig_start be able to add library dependencies? 79 | if (target.getOs().tag == .windows) { 80 | exe.linkSystemLibrary("ntdll"); 81 | exe.linkSystemLibrary("kernel32"); 82 | } 83 | 84 | const step = b.step("busybox", "build busybox and it's applets"); 85 | step.dependOn(&install.step); 86 | 87 | return exe; 88 | } 89 | -------------------------------------------------------------------------------- /capi.txt: -------------------------------------------------------------------------------- 1 | c89 2 | define NULL ((void*)0) 3 | header stdio 4 | header stdlib 5 | header string 6 | header time 7 | header locale 8 | 9 | c89 10 | define SEEK_SET 0 11 | header stdio 12 | -------------------------------------------------------------------------------- /filecheck.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | const Time = i128; 4 | 5 | pub fn leftFileIsNewer(left: []const u8, right: []const u8) !bool { 6 | const left_modify_time = (try getModifyTime(left)) orelse return false; 7 | const right_modify_time = (try getModifyTime(right)) orelse return false; 8 | // NOTE: '>' is 'safer' but could be overzealous rather than just '>=' 9 | return left_modify_time > right_modify_time; 10 | } 11 | 12 | pub fn getModifyTime(path: []const u8) !?Time { 13 | const file = std.fs.cwd().openFile(path, .{}) catch |err| switch (err) { 14 | error.FileNotFound => return null, 15 | else => return err, 16 | }; 17 | defer file.close(); 18 | return (try file.stat()).mtime; 19 | } 20 | -------------------------------------------------------------------------------- /gnumakebuild.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const GitRepoStep = @import("GitRepoStep.zig"); 3 | 4 | pub fn addGnuMake( 5 | b: *std.build.Builder, 6 | target: anytype, 7 | optimize: anytype, 8 | libc_only_std_static: *std.build.LibExeObjStep, 9 | zig_start: *std.build.LibExeObjStep, 10 | zig_posix: *std.build.LibExeObjStep, 11 | ) *std.build.LibExeObjStep { 12 | const repo = GitRepoStep.create(b, .{ 13 | .url = "https://git.savannah.gnu.org/git/make.git", 14 | .sha = "ed493f6c9116cc217b99c2cfa6a95f15803235a2", 15 | .branch = "4.4", 16 | }); 17 | 18 | const config_step = b.allocator.create(std.build.Step) catch unreachable; 19 | config_step.* = std.build.Step.init(.{ 20 | .id = .custom, 21 | .name = "configure GNU Make", 22 | .owner = b, 23 | }); 24 | // note: this MUST be the first dependency 25 | config_step.dependOn(&repo.step); 26 | 27 | const gen_config_h = b.addWriteFile(b.pathJoin(&.{ repo.path, "src", "config.h" }), 28 | \\/* Name of package */ 29 | \\#define PACKAGE "GNUMake" 30 | \\/* Define to the address where bug reports for this package should be sent. */ 31 | \\#define PACKAGE_BUGREPORT "dontsendmebugreports.com" 32 | \\/* Define to the full name of this package. */ 33 | \\#define PACKAGE_NAME "GNUMake" 34 | \\/* Define to the full name and version of this package. */ 35 | \\#define PACKAGE_STRING "GNUMake 4.4" 36 | \\/* Define to the one symbol short name of this package. */ 37 | \\#define PACKAGE_TARNAME "gnumake" 38 | \\/* Define to the home page for this package. */ 39 | \\#define PACKAGE_URL "https://www.gnu.org/software/make/" 40 | \\/* Define to the version of this package. */ 41 | \\#define PACKAGE_VERSION "4.4" 42 | \\ 43 | \\#define HAVE_STRING_H 1 44 | \\#define HAVE_STDLIB_H 1 45 | \\#define HAVE_INTTYPES_H 1 46 | \\#define HAVE_STDINT_H 1 47 | \\#define HAVE_SYS_TIME_H 1 48 | \\#define HAVE_DIRENT_H 1 49 | \\#define HAVE_FCNTL_H 1 50 | \\#define HAVE_ALLOCA_H 1 51 | \\#define HAVE_LOCALE_H 1 52 | \\#define HAVE_UNISTD_H 1 53 | \\#define HAVE_LIMITS_H 1 54 | \\#define HAVE_UMASK 1 55 | \\#define HAVE_MEMCPY 1 56 | \\#define HAVE_ATEXIT 1 57 | \\ 58 | \\#define FILE_TIMESTAMP_HI_RES 0 59 | \\/* not sure what this is, but default.c seems to need it */ 60 | \\#define SCCS_GET "get" 61 | \\ 62 | ); 63 | //\\#define __ptr_t char * 64 | //\\#define HAVE_GETOPT_H 1 65 | //\\#define HAVE_ALLOCA 1 66 | config_step.dependOn(&gen_config_h.step); 67 | // gcc -DHAVE_CONFIG_H -Isrc -I./src -Ilib -I./lib -DLIBDIR=\"/usr/local/lib\" -DLOCALEDIR=\"/usr/local/share/locale\" -DMAKE_MAINTAINER_MODE -C -Wall -Wextra -Werror -Wwrite-strings -Wshadow -Wdeclaration-after-statement -Wbad-function-cast -Wformat-security -Wtype-limits -Wunused-but-set-parameter -Wlogical-op -Wpointer-arith -Wignored-qualifiers -Wformat-signedness -Wduplicated-cond -g -O2 -MT src/hash.o -MD -MP -MF $depbase.Tpo -c -o src/hash.o src/hash.c &&\ 68 | 69 | // home/marler8997/zig/0.11.0-dev.12+ebf9ffd34/files/zig build-exe -cflags -std=c11 -- /home/marler8997/git/ziglibc/dep/make.git/src/ar.c /home/marler8997/git/ziglibc/dep/make.git/src/arscan.c /home/marler8997/git/ziglibc/dep/make.git/src/commands.c /home/marler8997/git/ziglibc/dep/make.git/src/default.c /home/marler8997/git/ziglibc/dep/make.git/src/dir.c /home/marler8997/git/ziglibc/dep/make.git/src/expand.c /home/marler8997/git/ziglibc/dep/make.git/src/file.c /home/marler8997/git/ziglibc/dep/make.git/src/function.c /home/marler8997/git/ziglibc/dep/make.git/src/getopt.c /home/marler8997/git/ziglibc/dep/make.git/src/getopt1.c /home/marler8997/git/ziglibc/dep/make.git/src/guile.c /home/marler8997/git/ziglibc/dep/make.git/src/hash.c /home/marler8997/git/ziglibc/dep/make.git/src/implicit.c /home/marler8997/git/ziglibc/dep/make.git/src/job.c /home/marler8997/git/ziglibc/dep/make.git/src/load.c /home/marler8997/git/ziglibc/dep/make.git/src/loadapi.c /home/marler8997/git/ziglibc/dep/make.git/src/main.c /home/marler8997/git/ziglibc/dep/make.git/src/misc.c /home/marler8997/git/ziglibc/dep/make.git/src/output.c /home/marler8997/git/ziglibc/dep/make.git/src/read.c /home/marler8997/git/ziglibc/dep/make.git/src/remake.c /home/marler8997/git/ziglibc/dep/make.git/src/rule.c /home/marler8997/git/ziglibc/dep/make.git/src/shuffle.c /home/marler8997/git/ziglibc/dep/make.git/src/signame.c /home/marler8997/git/ziglibc/dep/make.git/src/strcache.c /home/marler8997/git/ziglibc/dep/make.git/src/variable.c /home/marler8997/git/ziglibc/dep/make.git/src/version.c /home/marler8997/git/ziglibc/dep/make.git/src/vpath.c /home/marler8997/git/ziglibc/dep/make.git/src/posixos.c /home/marler8997/git/ziglibc/dep/make.git/src/remote-stub.c /home/marler8997/git/ziglibc/zig-cache/o/b2ab2b27dd98ed5352486d2081cf35bf/libc-only-std.a /home/marler8997/git/ziglibc/zig-cache/o/4d76e73699236d8f95a7f75ae51db269/libc-only-posix.a /home/marler8997/git/ziglibc/zig-cache/o/f647e7cbfedb41adc3d86981e126be58/libstart.a --verbose-cc --cache-dir /home/marler8997/git/ziglibc/zig-cache --global-cache-dir /home/marler8997/.cache/zig --name make -I /home/marler8997/git/ziglibc/inc/libc -I /home/marler8997/git/ziglibc/inc/posix -I /home/marler8997/git/ziglibc/inc/gnu --enable-cache 70 | 71 | const exe = b.addExecutable(.{ 72 | .name = "make", 73 | .target = target, 74 | .optimize = optimize, 75 | }); 76 | const install = b.addInstallArtifact(exe, .{}); 77 | exe.step.dependOn(&repo.step); 78 | exe.step.dependOn(config_step); 79 | const repo_path = repo.getPath(&exe.step); 80 | var files = std.ArrayList([]const u8).init(b.allocator); 81 | for (src_filenames) |src| { 82 | files.append(b.pathJoin(&.{ repo_path, "src", src })) catch unreachable; 83 | } 84 | 85 | exe.addIncludePath(.{ .path = b.pathJoin(&.{ repo_path, "src" }) }); 86 | exe.addCSourceFiles(files.toOwnedSlice() catch unreachable, &[_][]const u8{ 87 | "-std=c99", 88 | "-DHAVE_CONFIG_H", 89 | "-Wall", 90 | "-Wextra", 91 | "-Werror", 92 | "-Wwrite-strings", 93 | "-Wshadow", 94 | "-Wdeclaration-after-statement", 95 | "-Wbad-function-cast", 96 | "-Wformat-security", 97 | "-Wtype-limits", 98 | "-Wunused-but-set-parameter", 99 | "-Wpointer-arith", 100 | "-Wignored-qualifiers", 101 | // ignore unused parameter errors because the ATTRIBUTE define isn't working in makeint.h 102 | "-Wno-unused-parameter", 103 | "-Wno-dangling-else", 104 | //"-Wlogical-op", "-Wformat-signedness", "-Wduplicated-cond", 105 | }); 106 | 107 | exe.addIncludePath(.{ .path = "inc/libc" }); 108 | exe.addIncludePath(.{ .path = "inc/posix" }); 109 | exe.addIncludePath(.{ .path = "inc/gnu" }); 110 | exe.addIncludePath(.{ .path = "inc/alloca" }); 111 | exe.linkLibrary(libc_only_std_static); 112 | exe.linkLibrary(zig_start); 113 | exe.linkLibrary(zig_posix); 114 | // TODO: should libc_only_std_static and zig_start be able to add library dependencies? 115 | if (target.getOs().tag == .windows) { 116 | exe.linkSystemLibrary("ntdll"); 117 | exe.linkSystemLibrary("kernel32"); 118 | } 119 | 120 | const step = b.step("make", "build GNU make"); 121 | step.dependOn(&install.step); 122 | 123 | return exe; 124 | } 125 | 126 | const src_filenames = &[_][]const u8{ 127 | "ar.c", 128 | "arscan.c", 129 | "commands.c", 130 | "default.c", 131 | "dir.c", 132 | "expand.c", 133 | "file.c", 134 | "function.c", 135 | "getopt.c", 136 | "getopt1.c", 137 | "guile.c", 138 | "hash.c", 139 | "implicit.c", 140 | "job.c", 141 | "load.c", 142 | "loadapi.c", 143 | "main.c", 144 | "misc.c", 145 | "output.c", 146 | "read.c", 147 | "remake.c", 148 | "rule.c", 149 | "shuffle.c", 150 | "signame.c", 151 | "strcache.c", 152 | "variable.c", 153 | "version.c", 154 | "vpath.c", 155 | "posixos.c", 156 | "remote-stub.c", 157 | }; 158 | -------------------------------------------------------------------------------- /inc/alloca/alloca.h: -------------------------------------------------------------------------------- 1 | #ifndef _ALLOCA_H 2 | #define _ALLOCA_H 3 | 4 | #include "../libc/private/size_t.h" 5 | 6 | void *alloca(size_t); 7 | #define alloca __builtin_alloca 8 | 9 | #endif /* _ALLOCA_H */ 10 | -------------------------------------------------------------------------------- /inc/gnu/argp.h: -------------------------------------------------------------------------------- 1 | #ifndef _ARGP_H 2 | #define _ARGP_H 3 | 4 | #include "../libc/private/restrict.h" 5 | 6 | /* according to the GNU headers, error_t may be available in errno.h depending on the OS 7 | for now we'll just define it here */ 8 | typedef int error_t; 9 | 10 | struct argp_option { 11 | const char *name; 12 | int key; 13 | const char *arg; 14 | int flags; 15 | const char *doc; 16 | int group; 17 | }; 18 | 19 | #define OPTION_ARG_OPTIONAL 0x1 20 | #define OPTION_ALIAS 0x2 21 | 22 | #define ARGP_KEY_END 0x1000001 23 | #define ARGP_KEY_ARGS 0x1000006 24 | #define ARGP_KEY_NO_ARGS 0x1000002 25 | 26 | #define ARGP_ERR_UNKNOWN 999 /* TODO: what to put here? */ 27 | 28 | struct argp_state { 29 | int argc; 30 | char **argv; 31 | int next; 32 | unsigned flags; 33 | unsigned arg_num; 34 | void *input; 35 | }; 36 | 37 | typedef error_t (*argp_parser_t)(int key, char *arg, struct argp_state *state); 38 | 39 | struct argp { 40 | const struct argp_option *options; 41 | argp_parser_t parser; 42 | const char *args_doc; 43 | const char *doc; 44 | const struct argp_child *children; 45 | char *(*help_filter)(int key, const char *text, void *input); 46 | const char *argp_domain; 47 | }; 48 | 49 | void argp_usage(const struct argp_state *); 50 | error_t argp_parse( 51 | const struct argp *__zrestrict argp, 52 | int argc, 53 | char **__zrestrict argv, 54 | unsigned flags, 55 | int *__zrestrict arg_index, 56 | void *__zrestrict input); 57 | 58 | #endif /* _ARGP_H */ 59 | -------------------------------------------------------------------------------- /inc/gnu/getopt.h: -------------------------------------------------------------------------------- 1 | #ifndef _GETOPT_H 2 | #define _GETOPT_H 3 | 4 | /* GNU Make getopt.h checks for this define and will change the definition of getopt depending on it */ 5 | #define __GNU_LIBRARY__ 6 | 7 | #include "../posix/private/getopt.h" 8 | 9 | struct option { 10 | const char *name; 11 | int has_arg; 12 | int *flag; 13 | int val; 14 | }; 15 | 16 | int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex); 17 | int getopt_long_only(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex); 18 | 19 | #endif /* _GETOPT_H */ 20 | -------------------------------------------------------------------------------- /inc/gnu/glob.h: -------------------------------------------------------------------------------- 1 | #ifndef _GLOB_H 2 | #define _GLOB_H 3 | 4 | typedef struct { 5 | size_t gl_pathc; 6 | char **gl_pathv; 7 | size_t gl_offs; 8 | } glob_t; 9 | int glob( 10 | const char *restrict pattern, 11 | int flags, 12 | int(*errfunc)(const char *epath, int eerrno), 13 | glob_t *restrict pglob); 14 | void globfree(glob_t *pglob); 15 | 16 | // These are GNU extensions but go in the glob.h header file 17 | #if 1 18 | typedef char * __ptr_t; 19 | #endif 20 | 21 | 22 | #endif /* _GLOB_H */ 23 | -------------------------------------------------------------------------------- /inc/libc/assert.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASSERT_H 2 | #define _ASSERT_H 3 | 4 | #ifdef NDEBUG 5 | #define assert(ignore) ((void)0) 6 | #else 7 | #define assert(expression) ((void)((expression) || (__zassert_fail(#expression, __FILE__, __LINE__, __func__),0))) 8 | // TODO: mark __assert_fail as noreturn 9 | void __zassert_fail(const char *expression, const char *file, int line, const char *func); 10 | #endif 11 | 12 | #endif /* _ASSERT_H */ 13 | -------------------------------------------------------------------------------- /inc/libc/ctype.h: -------------------------------------------------------------------------------- 1 | #ifndef _CTYPE_H 2 | #define _CTYPE_H 3 | 4 | int isalnum(int c); 5 | int isalpha(int c); 6 | int iscntrl(int c); 7 | int isdigit(int c); 8 | int isgraph(int c); 9 | int islower(int c); 10 | int isprint(int c); 11 | int ispunct(int c); 12 | int isspace(int c); 13 | int isupper(int c); 14 | int isxdigit(int c); 15 | int tolower(int c); 16 | int toupper(int c); 17 | 18 | #if __STDC_VERSION__ >= 199901L 19 | int isblank(int c); 20 | #endif 21 | 22 | // NOTE: this stuff is defined by POSIX, not libc, but they need 23 | // to live in this header 24 | #if 1 25 | int isascii(int c); 26 | int toascii(int c); 27 | #endif 28 | 29 | 30 | #endif /* _CTYPE_H */ 31 | -------------------------------------------------------------------------------- /inc/libc/errno.h: -------------------------------------------------------------------------------- 1 | #ifndef _ERRNO_H 2 | #define _ERRNO_H 3 | 4 | extern int errno; 5 | 6 | #if __STDC_VERSION__ >= 199901L 7 | /* TODO: these can change based on platform */ 8 | #define EILSEQ 84 9 | #endif 10 | 11 | /* NOTE: these are defined by posix */ 12 | #if 1 13 | /* TODO: these can change based on platform, for now I'm just worrying about x86 */ 14 | #define EPERM 1 15 | #define ENOENT 2 16 | #define EINTR 4 17 | #define EAGAIN 11 18 | #define ENOMEM 12 19 | #define EACCES 13 20 | #define EEXIST 17 21 | #define EINVAL 22 22 | #define ENOTTY 25 23 | #define EPIPE 32 24 | #define EDOM 33 25 | #define ERANGE 34 26 | #define EWOULDBLOCK 140 27 | #define ECONNREFUSED 111 28 | #endif 29 | 30 | #endif /* _ERRNO_H */ 31 | -------------------------------------------------------------------------------- /inc/libc/float.h: -------------------------------------------------------------------------------- 1 | #ifndef _FLOAT_H 2 | #define _FLOAT_H 3 | 4 | #include "private/limits_and_float_shared.h" 5 | 6 | // TODO: I pulled these values from the C Standard, I need to look into them to see what 7 | // the values should actually be 8 | #define DBL_DIG 10 9 | #define DBL_EPSILON 1E-9 10 | #define DBL_MANT_DIG 53 11 | #define DBL_MAX 1E+37 12 | #define DBL_MAX_10_EXP 37 13 | #define DBL_MAX_EXP TODO_DEFINE_DBL_MAX_EXP 14 | #define DBL_MIN 1E-37 15 | #define DBL_MIN_10_EXP -37 16 | #define DBL_MIN_EXP TODO_DEFINE_DBL_MIN_EXP 17 | #define FLT_DIG 6 18 | #define FLT_EPSILON 1E-5 19 | #define FLT_MANT_DIG TODO_DEFINE_FLT_MANT_DIG 20 | #define FLT_MAX 1E+37 21 | #define FLT_MAX_10_EXP 37 22 | #define FLT_MAX_EXP TODO_DEFINE_FLT_MAX_EXP 23 | #define FLT_MIN 1E-37 24 | #define FLT_MIN_10_EXP -37 25 | #define FLT_MIN_EXP TODO_DEFINE_FLT_MIN_EXP 26 | #define FLT_RADIX 2 27 | #define FLT_ROUNDS TODO_DEFINE_FLT_ROUNDS 28 | #define LDBL_DIG 10 29 | #define LDBL_EPSILON 1E-9 30 | #define LDBL_MANT_DIG TODO_DEFINE_LDBL_MANT_DIG 31 | #define LDBL_MAX 1E+37 32 | #define LDBL_MAX_10_EXP 37 33 | #define LDBL_MAX_EXP TODO_DEFINE_LDBL_MAX_EXP 34 | #define LDBL_MIN 1E-37 35 | #define LDBL_MIN_10_EXP -37 36 | #define LDBL_MIN_EXP TODO_DEFINE_LDBL_MIN_EXP 37 | 38 | #if __STDC_VERSION__ >= 199901L 39 | #define FLT_EVAL_METHOD TODO_DEFINE_FLT_EVAL_METHOD 40 | #endif 41 | 42 | #endif /* _FLOAT_H */ 43 | -------------------------------------------------------------------------------- /inc/libc/inttypes.h: -------------------------------------------------------------------------------- 1 | #ifndef _INTTYPES_H 2 | #define _INTTYPES_H 3 | 4 | #if __STDC_VERSION__ < 199901L 5 | #error inttypes.h requires at least c99 I think 6 | #endif 7 | 8 | // most headers don't include other headers, but, this one by definition 9 | // also includes stdint.h and extends it 10 | #include "stdint.h" 11 | 12 | #define PRId32 "d" 13 | #define PRIx32 "x" 14 | 15 | #endif /* _INTTYPES_H */ 16 | -------------------------------------------------------------------------------- /inc/libc/limits.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIMITS_H 2 | #define _LIMITS_H 3 | 4 | #include "private/limits_and_float_shared.h" 5 | 6 | #if __STDC_VERSION__ >= 199901L 7 | /* assume 64-bit long long for now */ 8 | #define LLONG_MAX 9223372036854775807 9 | #define LLONG_MIN -9223372036854775807 10 | #define ULLONG_MAX 18446744073709551615 11 | #endif 12 | 13 | /* TODO: fixme */ 14 | /* TODO: I think PATH_MAX is supposed to be in "linux/limits.h" rather than "limits.h"?? */ 15 | #define PATH_MAX 1024 16 | 17 | #endif /* _LIMITS_H */ 18 | -------------------------------------------------------------------------------- /inc/libc/locale.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOCALE_H 2 | #define _LOCALE_H 3 | 4 | #include "private/null.h" 5 | 6 | #define LC_ALL 6 7 | #define LC_COLLATE 3 8 | #define LC_CTYPE 0 9 | #define LC_MONETARY 4 10 | #define LC_NUMERIC 1 11 | #define LC_TIME 2 12 | 13 | struct lconv { 14 | char *decimal_point; /* "." */ 15 | char *thousands_sep; /* "" */ 16 | char *grouping; /* "" */ 17 | char *int_curr_symbol; /* "" */ 18 | char *currency_symbol; /* "" */ 19 | char *mon_decimal_point; /* "" */ 20 | char *mon_thousands_sep; /* "" */ 21 | char *mon_grouping; /* "" */ 22 | char *positive_sign; /* "" */ 23 | char *negative_sign; /* "" */ 24 | char int_frac_digits; /* CHAR_MAX */ 25 | char frac_digits; /* CHAR_MAX */ 26 | char p_cs_precedes; /* CHAR_MAX */ 27 | char p_sep_by_space; /* CHAR_MAX */ 28 | char n_cs_precedes; /* CHAR_MAX */ 29 | char n_sep_by_space; /* CHAR_MAX */ 30 | char p_sign_posn; /* CHAR_MAX */ 31 | char n_sign_posn; /* CHAR_MAX */ 32 | }; 33 | 34 | char *setlocale(int category, const char *locale); 35 | struct lconv *localeconv(void); 36 | 37 | #endif /* _LOCALE_H */ 38 | -------------------------------------------------------------------------------- /inc/libc/math.h: -------------------------------------------------------------------------------- 1 | #ifndef _MATH_H 2 | #define _MATH_H 3 | 4 | #define HUGE_VAL ((double)INFINITY) 5 | #define HUGE_VALF ((float)INFINITY) 6 | #define HUGE_VALL ((long double)INFINITY) 7 | 8 | double acos(double x); 9 | double asin(double x); 10 | double atan(double x); 11 | double atan2(double y, double x); 12 | double cos(double x); 13 | double sin(double x); 14 | double tan(double x); 15 | double cosh(double x); 16 | double sinh(double x); 17 | double tanh(double x); 18 | double exp(double x); 19 | double frexp(double value, int *exp); 20 | double ldexp(double x, int exp); 21 | double log(double x); 22 | double log10(double x); 23 | double modf(double value, double *iptr); 24 | double pow(double x, double y); 25 | double sqrt(double x); 26 | double ceil(double x); 27 | double fabs(double x); 28 | double floor(double x); 29 | double fmod(double x, double y); 30 | 31 | #if __STDC_VERSION__ >= 199901L 32 | #define INFINITY __builtin_inff() 33 | double log2(double x); 34 | float log2f(float x); 35 | long double log2l(long double x); 36 | #endif 37 | 38 | #endif /* _MATH_H */ 39 | -------------------------------------------------------------------------------- /inc/libc/private/README.md: -------------------------------------------------------------------------------- 1 | The purpose of the private subdirectory is to hold headers that are private 2 | to the std headers (not accessible outside the std headers). 3 | 4 | I'm currently trying to organize the headers in such a way that none of the 5 | public headers depend on each other. This means that if one public header 6 | depends on something from another public header (i.e. stdio.h needs size_t 7 | from stdlib.h), then that common "thing" is moved to a private header 8 | included by both public headers. 9 | -------------------------------------------------------------------------------- /inc/libc/private/_zig_isize.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_ZIGISIZE_H 2 | #define _PRIVATE_ZIGISIZE_H 3 | 4 | // TODO: fixme 5 | #ifdef _WIN32 6 | typedef long long _zig_isize; 7 | #else 8 | 9 | // TODO: come up with a better way to do this 10 | #ifdef __x86_64__ 11 | typedef long _zig_isize; 12 | #else 13 | typedef int _zig_isize; 14 | #endif 15 | 16 | #endif 17 | 18 | #endif /* _PRIVATE_ZIGISIZE_H */ 19 | -------------------------------------------------------------------------------- /inc/libc/private/int16_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _INT16_T_H 2 | #define _INT16_T_H 3 | 4 | typedef short int16_t; 5 | 6 | #endif /* _INT16_T_H */ 7 | -------------------------------------------------------------------------------- /inc/libc/private/int32_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _INT32_T_H 2 | #define _INT32_T_H 3 | 4 | typedef int int32_t; 5 | 6 | #endif /* _INT32_T_H */ 7 | -------------------------------------------------------------------------------- /inc/libc/private/int64_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _INT64_T_H 2 | #define _INT64_T_H 3 | 4 | typedef long long int64_t; 5 | 6 | #endif /* _INT64_T_H */ 7 | -------------------------------------------------------------------------------- /inc/libc/private/int8_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _INT8_T_H 2 | #define _INT8_T_H 3 | 4 | typedef signed char int8_t; 5 | 6 | #endif /* _INT8_T_H */ 7 | -------------------------------------------------------------------------------- /inc/libc/private/limits_and_float_shared.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIMITS_AND_FLOAT_SHARED_H 2 | #define _LIMITS_AND_FLOAT_SHARED_H 3 | 4 | /* maximum number of bits for smallest object that is not a bit-field (byte) */ 5 | #define CHAR_BIT 8 6 | 7 | /* minimum value for an object of type signed char */ 8 | #define SCHAR_MIN -127 9 | 10 | /* maximum value for an object of type signed char */ 11 | #define SCHAR_MAX 127 12 | 13 | /* maximum value for an object of type unsigned char */ 14 | #define UCHAR_MAX 255 15 | 16 | /* if the 'char' type is unsigned */ 17 | /* #define CHAR_MIN 0 */ 18 | /* #define CHAR_MAX UCHAR_MAX */ 19 | /* if the 'char' type is signed */ 20 | #define CHAR_MIN SCHAR_MIN 21 | #define CHAR_MAX SCHAR_MAX 22 | 23 | /* maximum number of bytes in a multibyte character, for any supported locale MB_LEN_MAX 1 */ 24 | /* for now we assume wchar_t (multibyte characters) are 4 bytes */ 25 | #define MB_LEN_MAX 4 26 | 27 | /* minimum value for an object of type short int */ 28 | #define SHRT_MIN -32767 29 | 30 | /* maximum value for an object of type short int */ 31 | #define SHRT_MAX 32767 32 | 33 | /* maximum value for an object of type unsigned short int */ 34 | #define USHRT_MAX 65535 35 | 36 | /* minimum value for an object of type int */ 37 | /* assuming 32-bit int for now */ 38 | #define INT_MIN -2147483648 39 | 40 | /* maximum value for an object of type int */ 41 | /* assuming 32-bit int for now */ 42 | #define INT_MAX 2147483647 43 | 44 | /* maximum value for an object of type unsigned int */ 45 | /* assuming 32-bit unsigned for now */ 46 | #define UINT_MAX 0xffffffffU 47 | 48 | #ifdef _WIN32 49 | #define LONG_MIN (-2147483648L) 50 | #define LONG_MAX (0x7fffffffL) 51 | #define ULONG_MAX 0xffffffffUL 52 | #else 53 | #define LONG_MIN (-9223372036854775808L) 54 | #define LONG_MAX (0x7fffffffffffffffL) 55 | #define ULONG_MAX 0xffffffffffffffffUL 56 | #endif 57 | 58 | #endif /* _LIMITS_AND_FLOAT_SHARED_H */ 59 | -------------------------------------------------------------------------------- /inc/libc/private/noreturn.h: -------------------------------------------------------------------------------- 1 | #ifndef _NORETURN_H_ 2 | #define _NORETURN_H_ 3 | 4 | // TODO: change this depending on toolchain 5 | #define __znoreturn _Noreturn 6 | 7 | #endif /* _NORETURN_H_ */ 8 | -------------------------------------------------------------------------------- /inc/libc/private/null.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_NULL_H 2 | #define _PRIVATE_NULL_H 3 | 4 | #define NULL ((void*)0) 5 | 6 | #endif /* _PRIVATE_NULL_H */ 7 | -------------------------------------------------------------------------------- /inc/libc/private/restrict.h: -------------------------------------------------------------------------------- 1 | #ifndef _RESTRICT_H_ 2 | #define _RESTRICT_H_ 3 | 4 | #if __STDC_VERSION__ >= 199901L 5 | #define __zrestrict restrict 6 | #else 7 | #define __zrestrict 8 | #endif 9 | 10 | #endif /* _RESTRICT_H_ */ 11 | -------------------------------------------------------------------------------- /inc/libc/private/size_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_SIZET_H 2 | #define _PRIVATE_SIZET_H 3 | 4 | typedef __SIZE_TYPE__ size_t; 5 | 6 | #endif /* _PRIVATE_SIZET_H */ 7 | -------------------------------------------------------------------------------- /inc/libc/private/time_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_TIMET_H 2 | #define _PRIVATE_TIMET_H 3 | 4 | #include "../posix/private/ssize_t.h" 5 | 6 | typedef ssize_t time_t; 7 | 8 | #endif /* _PRIVATE_TIMET_H */ 9 | -------------------------------------------------------------------------------- /inc/libc/private/timespec.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_TIMEPEC_H 2 | #define _PRIVATE_TIMEPEC_H 3 | 4 | #if __STDC_VERSION__ >= 201112L 5 | #include "time_t.h" 6 | struct timespec { 7 | time_t tv_sec; // whole seconds >= 0 8 | long tv_nsec; // nanoseconds [0,999999999] 9 | }; 10 | #endif 11 | 12 | #endif /* _PRIVATE_TIMEPEC_H */ 13 | -------------------------------------------------------------------------------- /inc/libc/private/uint16_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _UINT16_T_H 2 | #define _UINT16_T_H 3 | 4 | typedef unsigned short uint16_t; 5 | 6 | #endif /* _UINT16_T_H */ 7 | -------------------------------------------------------------------------------- /inc/libc/private/uint32_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _UINT32_T_H 2 | #define _UINT32_T_H 3 | 4 | typedef unsigned uint32_t; 5 | 6 | #endif /* _UINT32_T_H */ 7 | -------------------------------------------------------------------------------- /inc/libc/private/uint64_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _UINT64_T_H 2 | #define _UINT64_T_H 3 | 4 | typedef unsigned long long uint64_t; 5 | // TODO: define this correctly 6 | #define UINT64_C(c) c ## ULL 7 | 8 | #endif /* _UINT64_T_H */ 9 | -------------------------------------------------------------------------------- /inc/libc/private/uint8_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _UINT8_T_H 2 | #define _UINT8_T_H 3 | 4 | typedef unsigned char uint8_t; 5 | 6 | #endif /* _UINT8_T_H */ 7 | -------------------------------------------------------------------------------- /inc/libc/private/valist.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_VALIST_H 2 | #define _PRIVATE_VALIST_H 3 | 4 | typedef __builtin_va_list va_list; 5 | 6 | #endif /* _PRIVATE_VALIST_H */ 7 | -------------------------------------------------------------------------------- /inc/libc/private/wchar_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _WCHAR_T 2 | #define _WCHAR_T 3 | 4 | typedef int wchar_t; 5 | 6 | #endif /* _WCHAR_T */ 7 | -------------------------------------------------------------------------------- /inc/libc/setjmp.h: -------------------------------------------------------------------------------- 1 | #ifndef _SETJMP_H 2 | #define _SETJMP_H 3 | 4 | #include "private/noreturn.h" 5 | 6 | #ifdef _WIN32 7 | typedef struct { void *stuff[40]; } jmp_buf; 8 | #else 9 | /* copied from musl, x86_64 setjmp.j */ 10 | typedef unsigned long __jmp_buf[8]; 11 | typedef struct __jmp_buf_tag { 12 | __jmp_buf __jb; 13 | unsigned long __fl; 14 | unsigned long __ss[128/sizeof(long)]; 15 | } jmp_buf[1]; 16 | #endif 17 | 18 | int setjmp(jmp_buf env); 19 | __znoreturn void longjmp(jmp_buf env, int val); 20 | 21 | #endif /* _SETJMP_H */ 22 | -------------------------------------------------------------------------------- /inc/libc/signal.h: -------------------------------------------------------------------------------- 1 | #ifndef _SIGNAL_H 2 | #define _SIGNAL_H 3 | 4 | #define SIG_ERR ((void (*)(int))-1) 5 | #define SIG_DFL ((void (*)(int)) 0) 6 | #define SIG_IGN ((void (*)(int)) 1) 7 | 8 | #define SIGINT 2 9 | 10 | typedef int sig_atomic_t; 11 | 12 | void (*signal(int sig, void (*func)(int)))(int); 13 | 14 | 15 | /* TODO: these are posix definitions for the signal.h libc header */ 16 | #if 1 17 | #include "private/restrict.h" 18 | #include "../posix/private/sigset_t.h" 19 | #include "../posix/private/pid_t.h" 20 | #include "../posix/private/uid_t.h" 21 | 22 | #define SIGALRM 14 23 | union sigval { 24 | int sival_int; 25 | void *sival_ptr; 26 | }; 27 | typedef struct { 28 | int si_signo; 29 | int si_code; 30 | int si_errno; 31 | pid_t si_pid; 32 | uid_t si_uid; 33 | void *si_addr; 34 | int si_status; 35 | long si_band; 36 | union sigval si_value; 37 | } siginfo_t; 38 | struct sigaction { 39 | void (*sa_handler)(int); 40 | sigset_t sa_mask; 41 | int sa_flags; 42 | void (*sa_sigaction)(int, siginfo_t *,void*); 43 | }; 44 | int sigaction( 45 | int sig, 46 | const struct sigaction *__zrestrict act, 47 | struct sigaction *__zrestrict oact); 48 | #endif 49 | 50 | 51 | #endif /* _SIGNAL_H */ 52 | -------------------------------------------------------------------------------- /inc/libc/stdarg.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDARG_H 2 | #define _STDARG_H 3 | 4 | #include "private/valist.h" 5 | 6 | #define va_start(ap, parmN) __builtin_va_start(ap, parmN) 7 | #define va_arg(ap, type) __builtin_va_arg(ap, type) 8 | #define va_end(ap) __builtin_va_end(ap) 9 | 10 | #endif /* _STDARG_H */ 11 | -------------------------------------------------------------------------------- /inc/libc/stddef.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDDEF_H 2 | #define _STDDEF_H 3 | 4 | #include "private/null.h" 5 | #include "private/size_t.h" 6 | #include "private/wchar_t.h" 7 | #include "private/_zig_isize.h" 8 | 9 | typedef _zig_isize ptrdiff_t; 10 | 11 | #define offsetof(type, member) __builtin_offsetof(type, member) 12 | 13 | #endif /* _STDDEF_H */ 14 | -------------------------------------------------------------------------------- /inc/libc/stdint.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDINT_H 2 | #define _STDINT_H 3 | 4 | #if __STDC_VERSION__ < 199901L 5 | #error stdint.h requires at least c99 I think 6 | #endif 7 | 8 | #include "private/int8_t.h" 9 | #include "private/uint8_t.h" 10 | #include "private/int16_t.h" 11 | #include "private/uint16_t.h" 12 | #include "private/int32_t.h" 13 | #include "private/uint32_t.h" 14 | #include "private/int64_t.h" 15 | #include "private/uint64_t.h" 16 | #include "private/_zig_isize.h" 17 | 18 | typedef int8_t int_least8_t; 19 | typedef int16_t int_least16_t; 20 | typedef int32_t int_least32_t; 21 | typedef int64_t int_least64_t; 22 | typedef uint8_t uint_least8_t; 23 | typedef uint16_t uint_least16_t; 24 | typedef uint32_t uint_least32_t; 25 | typedef uint64_t uint_least64_t; 26 | 27 | typedef int8_t int_fast8_t; 28 | typedef int16_t int_fast16_t; 29 | typedef int32_t int_fast32_t; 30 | typedef int64_t int_fast64_t; 31 | typedef uint8_t uint_fast8_t; 32 | typedef uint16_t uint_fast16_t; 33 | typedef uint32_t uint_fast32_t; 34 | typedef uint64_t uint_fast64_t; 35 | 36 | #define INT8_MIN (-128) 37 | #define INT8_MAX (0x7f) 38 | #define INT16_MIN (-32768) 39 | #define INT16_MAX (0x7fff) 40 | #define INT32_MIN (-2147483648) 41 | #define INT32_MAX (0x7fffffff) 42 | #define INT64_MIN (-9223372036854775807LL-1) 43 | #define INT64_MAX (0x7fffffffffffffffLL) 44 | 45 | #define UINT8_MAX (0xff) 46 | #define UINT16_MAX (0xffff) 47 | #define UINT32_MAX (0xffffffff) 48 | #define UINT64_MAX (0xffffffffffffffff) 49 | 50 | #define INT_LEAST8_MIN INT8_MIN 51 | #define INT_LEAST16_MIN INT16_MIN 52 | #define INT_LEAST32_MIN INT32_MIN 53 | #define INT_LEAST64_MIN INT64_MIN 54 | #define INT_LEAST8_MAX INT8_MAX 55 | #define INT_LEAST16_MAX INT16_MAX 56 | #define INT_LEAST32_MAX INT32_MAX 57 | #define INT_LEAST64_MAX INT64_MAX 58 | 59 | #define UINT_LEAST8_MIN UINT8_MIN 60 | #define UINT_LEAST16_MIN UINT16_MIN 61 | #define UINT_LEAST32_MIN UINT32_MIN 62 | #define UINT_LEAST64_MIN UINT64_MIN 63 | #define UINT_LEAST8_MAX UINT8_MAX 64 | #define UINT_LEAST16_MAX UINT16_MAX 65 | #define UINT_LEAST32_MAX UINT32_MAX 66 | #define UINT_LEAST64_MAX UINT64_MAX 67 | 68 | #define INT_FAST8_MIN INT8_MIN 69 | #define INT_FAST16_MIN INT16_MIN 70 | #define INT_FAST32_MIN INT32_MIN 71 | #define INT_FAST64_MIN INT64_MIN 72 | #define INT_FAST8_MAX INT8_MAX 73 | #define INT_FAST16_MAX INT16_MAX 74 | #define INT_FAST32_MAX INT32_MAX 75 | #define INT_FAST64_MAX INT64_MAX 76 | 77 | #define UINT_FAST8_MIN UINT8_MIN 78 | #define UINT_FAST16_MIN UINT16_MIN 79 | #define UINT_FAST32_MIN UINT32_MIN 80 | #define UINT_FAST64_MIN UINT64_MIN 81 | #define UINT_FAST8_MAX UINT8_MAX 82 | #define UINT_FAST16_MAX UINT16_MAX 83 | #define UINT_FAST32_MAX UINT32_MAX 84 | #define UINT_FAST64_MAX UINT64_MAX 85 | 86 | typedef long long intmax_t; 87 | typedef unsigned long long uintmax_t; 88 | typedef struct { intmax_t quot, rem; } imaxdiv_t; 89 | 90 | #if __STDC_VERSION__ >= 199901L 91 | typedef _zig_isize intptr_t; 92 | #endif 93 | 94 | #endif /* _STDINT_H */ 95 | -------------------------------------------------------------------------------- /inc/libc/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDIO_H 2 | #define _STDIO_H 3 | 4 | #include "private/null.h" 5 | #include "private/size_t.h" 6 | #include "private/valist.h" 7 | 8 | #define _IOFBF 0 9 | #define _IOLBF 1 10 | #define _IONBF 2 11 | #define BUFSIZ 1024 12 | 13 | #define SEEK_SET 0 14 | #define SEEK_CUR 1 15 | #define SEEK_END 2 16 | 17 | typedef struct { 18 | #ifdef _WIN32 19 | void* fd; 20 | #else 21 | int fd; 22 | #endif 23 | int errno; 24 | int eof; 25 | } FILE; 26 | 27 | typedef size_t fpos_t; 28 | 29 | /* a pointer to a single object T that cannot be null */ 30 | #define SINGLE_OBJECT_PTR(T, name) T name[static 1] 31 | 32 | #define EOF -1 33 | #define L_tmpnam 20 34 | 35 | extern FILE *const stdin; 36 | extern FILE *const stdout; 37 | extern FILE *const stderr; 38 | 39 | int remove(const char *filename); 40 | int rename(const char *old, const char *new); 41 | FILE *tmpfile(void); 42 | char *tmpnam(char *s); 43 | int fclose(FILE *stream); 44 | int fflush(FILE *stream); 45 | FILE *fopen(const char *filename, const char *mode); 46 | FILE *freopen(const char *filename, const char *mode, FILE *stream); 47 | void setbuf(FILE *stream, char *buf); 48 | int setvbuf(FILE *stream, char *buf, int mode, size_t size); 49 | int fprintf(FILE *stream, const char *format, ...); 50 | int fscanf(FILE *stream, const char *format, ...); 51 | int printf(const char *format, ...); 52 | int scanf(const char *format, ...); 53 | int sprintf(char *s, const char *format, ...); 54 | int sscanf(const char *s, const char *format, ...); 55 | //int vfprintf(FILE *stream, const char *format, va_list arg); 56 | int vprintf(const char *format, va_list arg); 57 | int vsprintf(char *s, const char *format, va_list arg); 58 | int fgetc(FILE *stream); 59 | char *fgets(char *s, int n, FILE *stream); 60 | int fputc(int c, FILE *stream); 61 | int fputs(const char *s, FILE *stream); 62 | int getc(FILE *stream); 63 | int getchar(void); 64 | char *gets(char *s); 65 | int putc(int c, FILE *stream); 66 | int putchar(int c); 67 | int puts(const char *s); 68 | int ungetc(int c, FILE *stream); 69 | size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); 70 | size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); 71 | int fgetpos(FILE *stream, fpos_t *pos); 72 | int fseek(FILE *stream, long int offset, int whence); 73 | int fsetpos(FILE *stream, const fpos_t *pos); 74 | long int ftell(FILE *stream); 75 | void rewind(FILE *stream); 76 | void clearerr(FILE *stream); 77 | int feof(FILE *stream); 78 | int ferror(FILE *stream); 79 | void perror(const char *s); 80 | 81 | #if __STDC_VERSION__ >= 199901L 82 | int snprintf(char * restrict s, size_t n, const char * restrict format, ...); 83 | int vsnprintf(char *restrict s, size_t n, const char * restrict format, va_list arg); 84 | #endif 85 | 86 | // NOTE: this stuff is defined by POSIX, not libc, but they need 87 | // to live in this header 88 | #if 1 89 | #define STDIN_FILENO 0 90 | #define STDOUT_FILENO 1 91 | #define STDERR_FILENO 2 92 | FILE *popen(const char *command, const char *mode); 93 | FILE *fdopen(int filedes, const char *mode); 94 | int fileno(FILE *stream); 95 | #endif 96 | 97 | // NOTE: this stuff is defined by linux, not libc, but they need 98 | // to live in this header 99 | #if 1 100 | #define FOPEN_MAX 999 101 | #endif 102 | 103 | #ifdef _WIN32 104 | int _fileno(FILE *); 105 | FILE *_popen(const char *command, const char *mode); 106 | int _pclose(FILE *); 107 | #endif 108 | 109 | #endif /* _STDIO_H */ 110 | -------------------------------------------------------------------------------- /inc/libc/stdlib.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDLIB_H 2 | #define _STDLIB_H 3 | 4 | #define EXIT_SUCCESS 0 5 | #define EXIT_FAILURE 1 6 | // TODO: look into this value more 7 | #define RAND_MAX 65535 8 | 9 | #include "private/null.h" 10 | #include "private/size_t.h" 11 | #include "private/wchar_t.h" 12 | 13 | typedef struct { int quot, rem; } div_t; 14 | typedef struct { long quot, rem; } ldiv_t; 15 | 16 | double atof(const char *nptr); 17 | int atoi(const char *nptr); 18 | long int atol(const char *nptr); 19 | double strtod(const char *nptr, char **endptr); 20 | long int strtol(const char *nptr, char **endptr, int base); 21 | unsigned long int strtoul(const char *nptr, char **endptr, int base); 22 | int rand(void); 23 | void srand(unsigned int seed); 24 | void *calloc(size_t nmemb, size_t size); 25 | void free(void *ptr); 26 | void *malloc(size_t size); 27 | void *realloc(void *ptr, size_t size); 28 | void abort(void); 29 | int atexit(void (*func)(void)); 30 | void exit(int status); 31 | char *getenv(const char *name); 32 | int system(const char *string); 33 | void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); 34 | void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); 35 | int abs(int j); 36 | div_t div(int numer, int denom); 37 | long int labs(long int j); 38 | ldiv_t ldiv(long int numer, long int denom); 39 | int mblen(const char *s, size_t n); 40 | int mbtowc(wchar_t *pwc, const char *s, size_t n); 41 | int wctomb(char *s, wchar_t wchar); 42 | size_t mbstowcs(wchar_t *pwcs, const char *s, size_t n); 43 | size_t wcstombs(char *s, const wchar_t *pwcs, size_t n); 44 | 45 | // NOTE: this stuff is defined by POSIX, not libc, but they need 46 | // to live in this header 47 | #if 1 48 | int mkstemp(char *template); 49 | #endif 50 | 51 | // NOTE: this stuff is defined by linux, not libc, but they need 52 | // to live in this header 53 | #if 1 54 | #define MB_CUR_MAX 1 55 | #endif 56 | 57 | #endif /* _STDLIB_H */ 58 | -------------------------------------------------------------------------------- /inc/libc/string.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRING_H 2 | #define _STRING_H 3 | 4 | #include "private/null.h" 5 | #include "private/size_t.h" 6 | 7 | void *memcpy(void *s1, const void *s2, size_t n); 8 | void *memmove(void *s1, const void *s2, size_t n); 9 | char *strcpy(char *s1, const char *s2); 10 | char *strncpy(char *s1, const char *s2, size_t n); 11 | char *strcat(char *s1, const char *s2); 12 | char *strncat(char *s1, const char *s2, size_t n); 13 | int memcmp(const void *s1, const void *s2, size_t n); 14 | int strcmp(const char *s1, const char *s2); 15 | int strcoll(const char *s1, const char *s2); 16 | int strncmp(const char *s1, const char *s2, size_t n); 17 | size_t strxfrm(char *s1, const char *s2, size_t n); 18 | void *memchr(const void *s, int c, size_t n); 19 | char *strchr(const char *s, int c); 20 | size_t strcspn(const char *s1, const char *s2); 21 | char *strpbrk(const char *s1, const char *s2); 22 | char *strrchr(const char *s, int c); 23 | size_t strspn(const char *s1, const char *s2); 24 | char *strstr(const char *s1, const char *s2); 25 | char *strtok(char *s1, const char *s2); 26 | void *memset(void *s, int c, size_t n); 27 | char *strerror(int errnum); 28 | size_t strlen(const char *s); 29 | 30 | // TODO: I'm not sure where strsignal comes from, it might 31 | // be GNU-specific but the libc-test project requires it 32 | // so I'm just inluding it for now. 33 | char* strsignal(int); 34 | 35 | // NOTE: it looks like strdup is defined by posix (not libc) 36 | // but it needs to be in string.h defined by libc (not posix) 37 | // so for now I'm just including it here 38 | char *strdup(const char *s); 39 | 40 | // NOTE: strlcpy and strlcat appear in some libc implementations (rejected by glibc though) 41 | // they don't appear to be a part of any standard. 42 | // It appears that the libc-test project expects them to be available in 43 | // however other docs put them in . 44 | #if 1 45 | size_t strlcpy(char *dst, const char *src, size_t size); 46 | size_t strlcat(char *dst, const char *src, size_t size); 47 | #endif 48 | 49 | 50 | #endif /* _STRING_H */ 51 | -------------------------------------------------------------------------------- /inc/libc/time.h: -------------------------------------------------------------------------------- 1 | #ifndef _TIME_H 2 | #define _TIME_H 3 | 4 | #include "private/null.h" 5 | #include "private/size_t.h" 6 | #include "private/time_t.h" 7 | #include "private/timespec.h" 8 | 9 | // CLK_TCK 10 | typedef long clock_t; 11 | struct tm { 12 | int tm_sec; /* seconds after the minute --- [0, 60] */ 13 | int tm_min; /* minutes after the hour --- [0, 59] */ 14 | int tm_hour; /* hours since midnight --- [0, 23] */ 15 | int tm_mday; /* day of the month --- [1, 31] */ 16 | int tm_mon; /* months since January --- [0, 11] */ 17 | int tm_year; /* years since 1900 */ 18 | int tm_wday; /* days since Sunday --- [0, 6] */ 19 | int tm_yday; /* days since January 1 --- [0, 365] */ 20 | int tm_isdst; /* Daylight Saving Time flag */ 21 | }; 22 | 23 | clock_t clock(void); 24 | double difftime(time_t time1, time_t time0); 25 | time_t mktime(struct tm *timeptr); 26 | time_t time(time_t *timer); 27 | char *asctime(const struct tm *timeptr); 28 | char *ctime(const time_t *timer); 29 | struct tm *gmtime(const time_t *timer); 30 | struct tm *localtime(const time_t *timer); 31 | size_t strftime(char *s, size_t maxsize, 32 | const char *format, const struct tm *timeptr); 33 | 34 | #if __STDC_VERSION__ >= 199901L 35 | #define CLOCKS_PER_SEC 1000000L 36 | #endif 37 | 38 | #if __STDC_VERSION__ >= 201112L 39 | #define TIME_UTC 1 40 | #endif 41 | // NOTE: it looks like the definitions in this block are defined by posix (not libc) 42 | // but they need to be in time.h defined by libc (not posix) 43 | // so for now I'm just including it here 44 | #if 1 45 | typedef int clockid_t; 46 | #define CLOCK_REALTIME 0 47 | #if __STDC_VERSION__ >= 201112L 48 | int clock_gettime(clockid_t clk_id, struct timespec *tp); 49 | #endif 50 | #endif 51 | 52 | #endif /* _TIME_H */ 53 | -------------------------------------------------------------------------------- /inc/linux/alloca.h: -------------------------------------------------------------------------------- 1 | #ifndef _ALLOCA_H 2 | #define _ALLOCA_H 3 | 4 | #include "../libc/private/size_t.h" 5 | 6 | void *alloca(size_t size); 7 | 8 | #endif /* _ALLOCA_H */ 9 | -------------------------------------------------------------------------------- /inc/linux/elf.h: -------------------------------------------------------------------------------- 1 | #ifndef _ELF_H 2 | #define _ELF_H 3 | 4 | #include "../libc/private/uint16_t.h" 5 | #include "../libc/private/uint32_t.h" 6 | #include "../libc/private/uint64_t.h" 7 | 8 | typedef uint32_t Elf32_Addr; 9 | typedef uint64_t Elf64_Addr; 10 | 11 | typedef uint32_t Elf32_Off; 12 | typedef uint64_t Elf64_Off; 13 | 14 | #define EI_MAG0 0 15 | #define EI_MAG1 1 16 | #define EI_MAG2 2 17 | #define EI_MAG3 3 18 | 19 | #define EI_CLASS 4 20 | #define ELFCLASSNONE 0 21 | #define ELFCLASS32 1 22 | #define ELFCLASS64 2 23 | #define ELFCLASSNUM 3 24 | 25 | #define EI_DATA 5 26 | #define ELFDATANONE 0 27 | #define ELFDATA2LSB 1 28 | #define ELFDATA2MSB 2 29 | #define ELFDATANUM 3 30 | 31 | #define EI_VERSION 6 32 | 33 | #define EV_NONE 0 34 | #define EV_CURRENT 1 35 | #define EV_NUM 2 36 | 37 | #define EI_OSABI 7 38 | #define ELFOSABI_NONE 0 39 | #define ELFOSABI_SYSV 0 40 | 41 | #define EI_ABIVERSION 8 42 | 43 | #define EI_PAD 9 44 | 45 | #define ET_NONE 0 46 | #define ET_REL 1 47 | #define ET_EXEC 2 48 | #define ET_DYN 3 49 | #define ET_CORE 4 50 | #define ET_NUM 5 51 | 52 | #define EM_X86_64 62 53 | 54 | #define EI_NIDENT 16 55 | typedef struct { 56 | unsigned char e_ident[EI_NIDENT]; 57 | uint16_t e_type; 58 | uint16_t e_machine; 59 | uint32_t e_version; 60 | Elf32_Addr e_entry; 61 | Elf32_Off e_phoff; 62 | Elf32_Off e_shoff; 63 | uint32_t e_flags; 64 | uint16_t e_ehsize; 65 | uint16_t e_phentsize; 66 | uint16_t e_phnum; 67 | uint16_t e_shentsize; 68 | uint16_t e_shnum; 69 | uint16_t e_shstrndx; 70 | } Elf32_Ehdr; 71 | typedef struct { 72 | unsigned char e_ident[EI_NIDENT]; 73 | uint16_t e_type; 74 | uint16_t e_machine; 75 | uint32_t e_version; 76 | Elf64_Addr e_entry; 77 | Elf64_Off e_phoff; 78 | Elf64_Off e_shoff; 79 | uint32_t e_flags; 80 | uint16_t e_ehsize; 81 | uint16_t e_phentsize; 82 | uint16_t e_phnum; 83 | uint16_t e_shentsize; 84 | uint16_t e_shnum; 85 | uint16_t e_shstrndx; 86 | } Elf64_Ehdr; 87 | 88 | #define SHN_UNDEF 0 89 | #define SHN_LORESERVE 0xff00 90 | #define SHN_XINDEX 0xffff 91 | 92 | #define SHT_NULL 0 93 | #define SHT_PROGBITS 1 94 | #define SHT_STRTAB 3 95 | 96 | #define SHF_WRITE 0x1 97 | #define SHF_ALLOC 0x2 98 | #define SHF_EXECINSTR 0x4 99 | 100 | typedef struct { 101 | uint32_t sh_name; 102 | uint32_t sh_type; 103 | uint32_t sh_flags; 104 | Elf32_Addr sh_addr; 105 | Elf32_Off sh_offset; 106 | uint32_t sh_size; 107 | uint32_t sh_link; 108 | uint32_t sh_info; 109 | uint32_t sh_addralign; 110 | uint32_t sh_entsize; 111 | } Elf32_Shdr; 112 | typedef struct { 113 | uint32_t sh_name; 114 | uint32_t sh_type; 115 | uint64_t sh_flags; 116 | Elf64_Addr sh_addr; 117 | Elf64_Off sh_offset; 118 | uint64_t sh_size; 119 | uint32_t sh_link; 120 | uint32_t sh_info; 121 | uint64_t sh_addralign; 122 | uint64_t sh_entsize; 123 | } Elf64_Shdr; 124 | 125 | 126 | #define PT_NULL 0 127 | #define PT_LOAD 1 128 | #define PT_DYNAMIC 2 129 | #define PT_INTERP 3 130 | 131 | #define PN_XNUM 0xffff 132 | 133 | #define PF_X 0x1 134 | #define PF_W 0x2 135 | #define PF_R 0x4 136 | 137 | typedef struct { 138 | uint32_t p_type; 139 | Elf32_Off p_offset; 140 | Elf32_Addr p_vaddr; 141 | Elf32_Addr p_paddr; 142 | uint32_t p_filesz; 143 | uint32_t p_memsz; 144 | uint32_t p_flags; 145 | uint32_t p_align; 146 | } Elf32_Phdr; 147 | typedef struct { 148 | uint32_t p_type; 149 | uint32_t p_flags; 150 | Elf64_Off p_offset; 151 | Elf64_Addr p_vaddr; 152 | Elf64_Addr p_paddr; 153 | uint64_t p_filesz; 154 | uint64_t p_memsz; 155 | uint64_t p_align; 156 | } Elf64_Phdr; 157 | 158 | #endif /* _ELF_H */ 159 | -------------------------------------------------------------------------------- /inc/linux/endian.h: -------------------------------------------------------------------------------- 1 | #ifndef _ENDIAN_H 2 | #define _ENDIAN_H 3 | 4 | #include "../libc/private/uint16_t.h" 5 | #include "../libc/private/uint32_t.h" 6 | #include "../libc/private/uint64_t.h" 7 | 8 | uint16_t htobe16(uint16_t host_16bits); 9 | uint16_t htole16(uint16_t host_16bits); 10 | uint16_t be16toh(uint16_t big_endian_16bits); 11 | uint16_t le16toh(uint16_t little_endian_16bits); 12 | 13 | uint32_t htobe32(uint32_t host_32bits); 14 | uint32_t htole32(uint32_t host_32bits); 15 | uint32_t be32toh(uint32_t big_endian_32bits); 16 | uint32_t le32toh(uint32_t little_endian_32bits); 17 | 18 | uint64_t htobe64(uint64_t host_64bits); 19 | uint64_t htole64(uint64_t host_64bits); 20 | uint64_t be64toh(uint64_t big_endian_64bits); 21 | uint64_t le64toh(uint64_t little_endian_64bits); 22 | 23 | #endif /* _ENDIAN_H */ 24 | -------------------------------------------------------------------------------- /inc/linux/values.h: -------------------------------------------------------------------------------- 1 | #ifndef _VALUES_H 2 | #define _VALUES_H 3 | 4 | // TODO: change these depending on platform 5 | #define MAXCHAR ((char)0x7f) 6 | #define MAXSHORT ((short)0x7fff) 7 | #define MAXINT ((int)0x7fffffff) 8 | #define MAXLONG ((long)0x7fffffff) 9 | #define MINCHAR ((char)0x80) 10 | #define MINSHORT ((short)0x8000) 11 | #define MININT ((int)0x80000000) 12 | #define MINLONG ((long)0x80000000) 13 | 14 | #endif /* _VALUES_H */ 15 | -------------------------------------------------------------------------------- /inc/posix/ar.h: -------------------------------------------------------------------------------- 1 | #ifndef _AR_H 2 | #define _AR_H 3 | 4 | /* NOTE: I'm not sure whether this is actually apart of any POSIX standard 5 | I found its original use inside of GNU Make arscan.c, which thinks that all 6 | platforms have it except for Windows/Android/BEOS. 7 | */ 8 | 9 | #endif /* _AR_H */ 10 | -------------------------------------------------------------------------------- /inc/posix/arpa/inet.h: -------------------------------------------------------------------------------- 1 | #ifndef _ARPA_INET_H 2 | #define _ARPA_INET_H 3 | 4 | #include "../../libc/private/uint16_t.h" 5 | #include "../../libc/private/uint32_t.h" 6 | 7 | uint32_t htonl(uint32_t hostlong); 8 | uint16_t htons(uint16_t hostshort); 9 | uint32_t ntohl(uint32_t netlong); 10 | uint16_t ntohs(uint16_t netshort); 11 | 12 | in_addr_t inet_addr(const char *cp); 13 | char *inet_ntoa(struct in_addr in); 14 | 15 | #endif /* _ARPA_INET_H */ 16 | -------------------------------------------------------------------------------- /inc/posix/dirent.h: -------------------------------------------------------------------------------- 1 | #ifndef _DIRENT_H 2 | #define _DIRENT_H 3 | 4 | #include "private/ino_t.h" 5 | 6 | typedef struct DIR DIR; 7 | struct dirent { 8 | ino_t d_ino; 9 | char d_name[]; 10 | }; 11 | 12 | DIR *opendir(const char *dirname); 13 | int closedir(DIR *); 14 | DIR *fdopendir(int fd); 15 | 16 | struct dirent *readdir(DIR *); 17 | 18 | #endif /* _DIRENT_H */ 19 | -------------------------------------------------------------------------------- /inc/posix/fcntl.h: -------------------------------------------------------------------------------- 1 | #ifndef _FCNTL_H 2 | #define _FCNTL_H 3 | 4 | #define O_RDONLY 0 5 | #define O_WRONLY 01 6 | #define O_RDWR 02 7 | #define O_APPEND 010 8 | #define O_CREAT 0100 9 | #define O_EXCL 0200 10 | #define O_TRUNC 01000 11 | #define O_NONBLOCK 04000 12 | #define O_CLOEXEC 02000000 13 | #define O_EXEC 010000000 14 | 15 | int open(const char *path, int oflag, ...); 16 | int openat(int fd, const char *path, int oflag, ...); 17 | 18 | // -------------------------------------------------------------------------------- 19 | // NOTE: fcntl and the F_* constants may also optionally be in unistd.h according to the posix docs 20 | // -------------------------------------------------------------------------------- 21 | #define F_DUPFD 0 22 | #define F_GETFD 1 23 | #define F_SETFD 2 24 | #define F_GETFL 3 25 | #define F_SETFL 4 26 | #define F_GETOWN 5 27 | #define F_SETOWN 6 28 | #define FD_CLOEXEC 1 29 | int fcntl(int fildes, int cmd, ...); 30 | // -------------------------------------------------------------------------------- 31 | // -------------------------------------------------------------------------------- 32 | // -------------------------------------------------------------------------------- 33 | 34 | #endif /* _FCNTL_H */ 35 | -------------------------------------------------------------------------------- /inc/posix/inttypes.h: -------------------------------------------------------------------------------- 1 | #ifndef _INTTYPES_H 2 | #define _INTTYPES_H 3 | 4 | typedef long long intmax_t; 5 | 6 | #endif /* _INTTYPES_H */ 7 | -------------------------------------------------------------------------------- /inc/posix/libgen.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIBGEN_H 2 | #define _LIBGEN_H 3 | 4 | char *basename(char *); 5 | char *dirname(char *); 6 | 7 | #endif /* _LIBGEN_H */ 8 | -------------------------------------------------------------------------------- /inc/posix/locale.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOCALE_H 2 | #define _LOCALE_H 3 | 4 | #include "private/locale_t.h" 5 | 6 | #endif /* _LOCALE_H */ 7 | -------------------------------------------------------------------------------- /inc/posix/netdb.h: -------------------------------------------------------------------------------- 1 | #ifndef _NETDB_H 2 | #define _NETDB_H 3 | 4 | #include "private/socklen_t.h" 5 | 6 | struct hostent { 7 | char *h_name; 8 | char **h_aliases; 9 | int h_addrtype; 10 | int h_length; 11 | char **h_addr_list; 12 | }; 13 | 14 | struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type); 15 | struct hostent *gethostbyname(const char *name); 16 | 17 | #endif /* _NETDB_H */ 18 | -------------------------------------------------------------------------------- /inc/posix/netinet/in.h: -------------------------------------------------------------------------------- 1 | #ifndef _NETINET_IN_H 2 | #define _NETINET_IN_H 3 | 4 | #include "../../libc/private/uint8_t.h" 5 | #include "../../libc/private/uint32_t.h" 6 | #include "../private/sockaddr.h" 7 | #include "../private/in_addr_t.h" 8 | 9 | #define IPPORT_RESERVED 1024 10 | #define IPPORT_USERRESERVED 5000 11 | 12 | #define IPPROTO_IP 0 13 | #define IPPROTO_TCP 6 14 | #define IPPROTO_UDP 17 15 | 16 | #define INADDR_ANY 0 17 | 18 | struct in_addr { 19 | in_addr_t s_addr; 20 | }; 21 | 22 | #define INADDR_LOOPBACK ((in_addr_t)0x7f000001) 23 | 24 | // TODO: define me better 25 | struct sockaddr_in { 26 | int sin_family; 27 | int sin_port; 28 | struct in_addr sin_addr; 29 | uint8_t sin_zero[8]; 30 | }; 31 | 32 | 33 | #endif /* _NETINET_IN_H */ 34 | -------------------------------------------------------------------------------- /inc/posix/netinet/tcp.h: -------------------------------------------------------------------------------- 1 | #ifndef _NETINET_TCP_H 2 | #define _NETINET_TCP_H 3 | 4 | #define TCP_NODELAY 1 5 | 6 | #endif /* _NETINET_TCP_H */ 7 | -------------------------------------------------------------------------------- /inc/posix/paths.h: -------------------------------------------------------------------------------- 1 | #ifndef _PATHS_H_ 2 | #define _PATHS_H_ 3 | 4 | // TODO: what standard is this defined in? 5 | // It's used by yacc, and I see a definition from oracle here: 6 | // https://docs.oracle.com/cd/E86824_01/html/E54772/paths.h-3head.html 7 | #define _PATH_DEFPATH "/usr/local/bin:/bin:/usr/bin" 8 | #define _PATH_STDPATH "/bin:/usr/bin:/sbin:/usr/sbin" 9 | 10 | #define _PATH_BSHELL "/bin/sh" 11 | #define _PATH_CONSOLE "/dev/console" 12 | #define _PATH_DEVNULL "/dev/null" 13 | #define _PATH_KLOG "/proc/kmsg" 14 | #define _PATH_LASTLOG "/var/log/lastlog" 15 | #define _PATH_MAILDIR "/var/mail" 16 | #define _PATH_MAN "/usr/share/man" 17 | #define _PATH_MNTTAB "/etc/fstab" 18 | #define _PATH_MOUNTED "/etc/mtab" 19 | #define _PATH_NOLOGIN "/etc/nologin" 20 | #define _PATH_SENDMAIL "/usr/sbin/sendmail" 21 | #define _PATH_SHADOW "/etc/shadow" 22 | #define _PATH_SHELLS "/etc/shells" 23 | #define _PATH_TTY "/dev/tty" 24 | #define _PATH_UTMP "/dev/null/utmp" 25 | #define _PATH_VI "/usr/bin/vi" 26 | #define _PATH_WTMP "/dev/null/wtmp" 27 | 28 | #define _PATH_DEV "/dev/" 29 | #define _PATH_TMP "/tmp/" 30 | #define _PATH_VARDB "/var/lib/misc/" 31 | #define _PATH_VARRUN "/var/run/" 32 | #define _PATH_VARTMP "/var/tmp/" 33 | 34 | #endif /* _PATHS_H_ */ 35 | -------------------------------------------------------------------------------- /inc/posix/private/blkcnt_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_BLKCNT_T_H 2 | #define _PRIVATE_BLKCNT_T_H 3 | 4 | typedef int blkcnt_t; // TODO: look into this type more 5 | 6 | #endif /* _PRIVATE_BLKCNT_T_H */ 7 | -------------------------------------------------------------------------------- /inc/posix/private/blksize_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_BLKSIZE_T_H 2 | #define _PRIVATE_BLKSIZE_T_H 3 | 4 | typedef int blksize_t; // TODO: look into this type more 5 | 6 | #endif /* _PRIVATE_BLKSIZE_T_H */ 7 | -------------------------------------------------------------------------------- /inc/posix/private/dev_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_DEV_T_H 2 | #define _PRIVATE_DEV_T_H 3 | 4 | typedef int dev_t; // TODO: look into this type more 5 | 6 | #endif /* _PRIVATE_DEV_T_H */ 7 | -------------------------------------------------------------------------------- /inc/posix/private/fd_set.h: -------------------------------------------------------------------------------- 1 | #ifndef _FD_SET_H 2 | #define _FD_SET_H 3 | 4 | #define FD_SETSIZE 1024 5 | // TODO: fixme 6 | typedef struct { 7 | unsigned fds_bits[FD_SETSIZE / (sizeof(unsigned) * 8)]; 8 | } fd_set; 9 | 10 | #endif /* _FD_SET_H */ 11 | -------------------------------------------------------------------------------- /inc/posix/private/getopt.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_GETOPT_H 2 | #define _PRIVATE_GETOPT_H 3 | 4 | extern char *optarg; 5 | extern int opterr, optind, optopt; 6 | int getopt(int, char * const [], const char *); 7 | 8 | #endif /* _PRIVATE_GETOPT_H */ 9 | -------------------------------------------------------------------------------- /inc/posix/private/gid_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_GID_T_H 2 | #define _PRIVATE_GID_T_H 3 | 4 | typedef int gid_t; // TODO: look into this type more 5 | 6 | #endif /* _PRIVATE_GID_T_H */ 7 | -------------------------------------------------------------------------------- /inc/posix/private/in_addr_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_IN_ADDR_T_H 2 | #define _PRIVATE_IN_ADDR_T_H 3 | 4 | #include "../../libc/private/uint32_t.h" 5 | 6 | typedef uint32_t in_addr_t; 7 | 8 | #endif /* _PRIVATE_IN_ADDR_T_H */ 9 | 10 | -------------------------------------------------------------------------------- /inc/posix/private/ino_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_INO_T_H 2 | #define _PRIVATE_INO_T_H 3 | 4 | typedef int ino_t; // TODO: look into this type more 5 | 6 | #endif /* _PRIVATE_INO_T_H */ 7 | -------------------------------------------------------------------------------- /inc/posix/private/ipc_perm.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_IPC_PERM_H 2 | #define _PRIVATE_IPC_PERM_H 3 | 4 | #include "uid_t.h" 5 | #include "gid_t.h" 6 | #include "mode_t.h" 7 | 8 | struct ipc_perm { 9 | uid_t uid; 10 | gid_t gid; 11 | uid_t cuid; 12 | gid_t cgid; 13 | mode_t mode; 14 | }; 15 | 16 | #endif /* _PRIVATE_IPC_PERM_H */ 17 | -------------------------------------------------------------------------------- /inc/posix/private/key_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_KEY_T_H 2 | #define _PRIVATE_KEY_T_H 3 | 4 | typedef int key_t; // TODO: look into this type more 5 | 6 | #endif /* _PRIVATE_KEY_T_H */ 7 | -------------------------------------------------------------------------------- /inc/posix/private/locale_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_LOCALE_T_H 2 | #define _PRIVATE_LOCALE_T_H 3 | 4 | typedef int locale_t; // TODO: look into this type more 5 | 6 | #endif /* _PRIVATE_LOCALE_T_H */ 7 | -------------------------------------------------------------------------------- /inc/posix/private/mode_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_MODE_T_H 2 | #define _PRIVATE_MODE_T_H 3 | 4 | typedef unsigned mode_t; // TODO: look into this type more 5 | 6 | #endif /* _PRIVATE_MODE_T_H */ 7 | -------------------------------------------------------------------------------- /inc/posix/private/nlink_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_NLINK_T_H 2 | #define _PRIVATE_NLINK_T_H 3 | 4 | typedef int nlink_t; // TODO: look into this type more 5 | 6 | #endif /* _PRIVATE_NLINK_T_H */ 7 | -------------------------------------------------------------------------------- /inc/posix/private/off_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_OFF_T_H 2 | #define _PRIVATE_OFF_T_H 3 | 4 | typedef int off_t; // TODO: look into this type more 5 | 6 | #endif /* _PRIVATE_OFF_T_H */ 7 | -------------------------------------------------------------------------------- /inc/posix/private/pid_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_PID_T_H 2 | #define _PRIVATE_PID_T_H 3 | 4 | typedef int pid_t; // TODO: look into this type more 5 | 6 | #endif /* _PRIVATE_PID_T_H */ 7 | -------------------------------------------------------------------------------- /inc/posix/private/sa_family_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_SA_FAMILY_T_H 2 | #define _PRIVATE_SA_FAMILY_T_H 3 | 4 | /* todo: define me better */ 5 | typedef int sa_family_t; 6 | 7 | #endif /* _PRIVATE_SA_FAMILY_T_H */ 8 | -------------------------------------------------------------------------------- /inc/posix/private/sigset_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_SIGSET_T_H 2 | #define _PRIVATE_SIGSET_T_H 3 | 4 | typedef struct { unsigned long __signals; } sigset_t; 5 | 6 | #endif /* _PRIVATE_SIGSET_T_H */ 7 | -------------------------------------------------------------------------------- /inc/posix/private/sockaddr.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_SOCKADDR_H 2 | #define _PRIVATE_SOCKADDR_H 3 | 4 | #include "sa_family_t.h" 5 | 6 | // TODO: define me better 7 | struct sockaddr { 8 | sa_family_t sa_family; 9 | char reserved[100]; 10 | }; 11 | 12 | #endif /* _PRIVATE_SOCKADDR_H */ 13 | -------------------------------------------------------------------------------- /inc/posix/private/socklen_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_SOCKLEN_T_H 2 | #define _PRIVATE_SOCKLEN_T_H 3 | 4 | /* todo: define me better */ 5 | typedef int socklen_t; 6 | 7 | #endif /* _PRIVATE_SOCKLEN_T_H */ 8 | -------------------------------------------------------------------------------- /inc/posix/private/ssize_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_SSIZET_H 2 | #define _PRIVATE_SSIZET_H 3 | 4 | #include "../../libc/private/_zig_isize.h" 5 | 6 | typedef _zig_isize ssize_t; 7 | 8 | #endif /* _PRIVATE_SSIZET_H */ 9 | -------------------------------------------------------------------------------- /inc/posix/private/suseconds_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_SUSECONDS_H 2 | #define _PRIVATE_SUSECONDS_H 3 | 4 | // TODO: fixme 5 | typedef int suseconds_t; 6 | 7 | #endif /* _PRIVATE_SUSECONDS_H */ 8 | -------------------------------------------------------------------------------- /inc/posix/private/timeval.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_TIMEVAL_H 2 | #define _PRIVATE_TIMEVAL_H 3 | 4 | #include "../../libc/private/time_t.h" 5 | #include "suseconds_t.h" 6 | 7 | struct timeval { 8 | time_t tv_sec; 9 | suseconds_t tv_usec; 10 | }; 11 | 12 | #endif /* _PRIVATE_TIMEVAL_H */ 13 | -------------------------------------------------------------------------------- /inc/posix/private/uid_t.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIVATE_UID_T_H 2 | #define _PRIVATE_UID_T_H 3 | 4 | typedef int uid_t; // TODO: look into this type more 5 | 6 | #endif /* _PRIVATE_UID_T_H */ 7 | -------------------------------------------------------------------------------- /inc/posix/pthread.h: -------------------------------------------------------------------------------- 1 | #ifndef _PTHREAD_H 2 | #define _PTHREAD_H 3 | 4 | #define PTHREAD_BARRIER_SERIAL_THREAD TODO_DEFINE_PTHREAD_BARRIER_SERIAL_THREAD 5 | #define PTHREAD_CANCEL_ASYNCHRONOU TODO_DEFINE_PTHREAD_CANCEL_ASYNCHRONOUS 6 | #define PTHREAD_CANCEL_ENABL TODO_DEFINE_PTHREAD_CANCEL_ENABLE 7 | #define PTHREAD_CANCEL_DEFERRE TODO_DEFINE_PTHREAD_CANCEL_DEFERRED 8 | #define PTHREAD_CANCEL_DISABL TODO_DEFINE_PTHREAD_CANCEL_DISABLE 9 | #define PTHREAD_CANCELE TODO_DEFINE_PTHREAD_CANCELED 10 | #define PTHREAD_CREATE_DETACHE TODO_DEFINE_PTHREAD_CREATE_DETACHED 11 | #define PTHREAD_CREATE_JOINABL TODO_DEFINE_PTHREAD_CREATE_JOINABLE 12 | #define PTHREAD_EXPLICIT_SCHE TODO_DEFINE_PTHREAD_EXPLICIT_SCHED 13 | #define PTHREAD_INHERIT_SCHE TODO_DEFINE_PTHREAD_INHERIT_SCHED 14 | #define PTHREAD_MUTEX_DEFAUL TODO_DEFINE_PTHREAD_MUTEX_DEFAULT 15 | #define PTHREAD_MUTEX_ERRORCHEC TODO_DEFINE_PTHREAD_MUTEX_ERRORCHECK 16 | #define PTHREAD_MUTEX_NORMA TODO_DEFINE_PTHREAD_MUTEX_NORMAL 17 | #define PTHREAD_MUTEX_RECURSIV TODO_DEFINE_PTHREAD_MUTEX_RECURSIVE 18 | #define PTHREAD_MUTEX_ROBUS TODO_DEFINE_PTHREAD_MUTEX_ROBUST 19 | #define PTHREAD_MUTEX_STALLE TODO_DEFINE_PTHREAD_MUTEX_STALLED 20 | #define PTHREAD_ONCE_INI TODO_DEFINE_PTHREAD_ONCE_INIT 21 | #define PTHREAD_PRIO_INHERI TODO_DEFINE_PTHREAD_PRIO_INHERIT 22 | #define PTHREAD_PRIO_NON TODO_DEFINE_PTHREAD_PRIO_NONE 23 | #define PTHREAD_PRIO_PROTEC TODO_DEFINE_PTHREAD_PRIO_PROTECT 24 | #define PTHREAD_PROCESS_SHARE TODO_DEFINE_PTHREAD_PROCESS_SHARED 25 | #define PTHREAD_PROCESS_PRIVAT TODO_DEFINE_PTHREAD_PROCESS_PRIVATE 26 | #define PTHREAD_SCOPE_PROCES TODO_DEFINE_PTHREAD_SCOPE_PROCESS 27 | #define PTHREAD_SCOPE_SYSTE TODO_DEFINE_PTHREAD_SCOPE_SYSTEM 28 | 29 | // TODO: define this properly 30 | typedef int pthread_attr_t; 31 | typedef int pthread_barrier_t; 32 | typedef int pthread_barrierattr_t; 33 | typedef int pthread_cond_t; 34 | typedef int pthread_condattr_t; 35 | typedef int pthread_key_t; 36 | typedef int pthread_mutex_t; 37 | typedef int pthread_mutexattr_t; 38 | typedef int pthread_once_t; 39 | typedef int pthread_rwlock_t; 40 | typedef int pthread_rwlockattr_t; 41 | typedef int pthread_spinlock_t; 42 | typedef int pthread_t; 43 | 44 | #define PTHREAD_MUTEX_INITIALIZER {0} 45 | int pthread_mutex_init(pthread_mutex_t *restrict, const pthread_mutexattr_t *restrict); 46 | int pthread_mutex_destroy(pthread_mutex_t *); 47 | int pthread_mutex_lock(pthread_mutex_t *); 48 | int pthread_mutex_unlock(pthread_mutex_t *); 49 | 50 | #define PTHREAD_COND_INITIALIZER {0} 51 | int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); 52 | int pthread_cond_destroy(pthread_cond_t *cond); 53 | int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); 54 | int pthread_cond_broadcast(pthread_cond_t *cond); 55 | int pthread_cond_signal(pthread_cond_t *cond); 56 | 57 | #endif /* _PTHREAD_H */ 58 | -------------------------------------------------------------------------------- /inc/posix/strings.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRINGS_H 2 | #define _STRINGS_H 3 | 4 | #include "private/locale_t.h" 5 | 6 | int strcasecmp(const char *s1, const char *s2); 7 | int strcasecmp_l(const char *s1, const char *s2, 8 | locale_t locale); 9 | int strncasecmp(const char *s1, const char *s2, size_t n); 10 | int strncasecmp_l(const char *s1, const char *s2, 11 | size_t n, locale_t locale); 12 | 13 | #endif /* _STRINGS_H */ 14 | -------------------------------------------------------------------------------- /inc/posix/sys/ioctl.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_IOCTL_H 2 | #define _SYS_IOCTL_H 3 | 4 | int ioctl(int filedes, int request, ...); 5 | 6 | // NOTE: this stuff is defined by linux, not posix, but they need 7 | // to live in this header 8 | #if 1 9 | // TODO: will change depending on platform 10 | #define FIONBIO 0x5421 11 | #endif 12 | 13 | 14 | #endif /* SYS_IOCTL_H */ 15 | -------------------------------------------------------------------------------- /inc/posix/sys/ipc.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_IPC_H 2 | #define _SYS_IPC_H 3 | 4 | #define IPC_RMID 0 5 | #define IPC_SET 1 6 | #define IPC_STAT 2 7 | #define IPC_INFO 3 8 | #define IPC_CREAT 4 9 | 10 | #endif /* SYS_IPC_H */ 11 | -------------------------------------------------------------------------------- /inc/posix/sys/param.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_PARAM_H 2 | #define _SYS_PARAM_H 3 | 4 | /* NOTE: I'm not sure who defines this, it's used by libxcb though */ 5 | 6 | #endif /* SYS_PARAM_H */ 7 | -------------------------------------------------------------------------------- /inc/posix/sys/resource.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_RESOURCE_H 2 | #define _SYS_RESOURCE_H 3 | 4 | 5 | 6 | #endif /* _SYS_RESOURCE_H */ 7 | -------------------------------------------------------------------------------- /inc/posix/sys/select.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_SELECT_H 2 | #define _SYS_SELECT_H 3 | 4 | // According to POSIX.1-2001 5 | #if 1 6 | #include "../../libc/private/timespec.h" 7 | #include "../private/fd_set.h" 8 | #include "../private/sigset_t.h" 9 | #include "../private/timeval.h" 10 | 11 | void FD_CLR(int fd, fd_set *fdset); 12 | int FD_ISSET(int fd, fd_set *fdset); 13 | void FD_SET(int fd, fd_set *fdset); 14 | void FD_ZERO(fd_set *fdset); 15 | 16 | int pselect(int, fd_set *restrict, fd_set *restrict, fd_set *restrict, 17 | const struct timespec *restrict, const sigset_t *restrict); 18 | int select(int, fd_set *restrict, fd_set *restrict, fd_set *restrict, 19 | struct timeval *restrict); 20 | #endif 21 | 22 | #endif /* _SYS_SELECT_H */ 23 | -------------------------------------------------------------------------------- /inc/posix/sys/shm.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_SHM_H 2 | #define _SYS_SHM_H 3 | 4 | #include "../../libc/private/size_t.h" 5 | #include "../../libc//private/time_t.h" 6 | #include "../private/pid_t.h" 7 | #include "../private/ipc_perm.h" 8 | 9 | typedef unsigned short shmatt_t; 10 | 11 | struct shmid_ds { 12 | struct ipc_perm shm_perm; 13 | size_t shm_segsz; 14 | pid_t shm_lpid; 15 | pid_t shm_cpid; 16 | shmatt_t shm_nattch; 17 | time_t shm_atime; 18 | time_t shm_dtime; 19 | time_t shm_ctime; 20 | }; 21 | 22 | #endif /* _SYS_SHM_H */ 23 | -------------------------------------------------------------------------------- /inc/posix/sys/socket.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_SOCKET_H 2 | #define _SYS_SOCKET_H 3 | 4 | #include "../../libc/private/restrict.h" 5 | #include "../../libc/private/size_t.h" 6 | #include "../private/ssize_t.h" 7 | #include "../private/socklen_t.h" 8 | #include "../private/sockaddr.h" 9 | 10 | #define SOCK_STREAM 1 11 | #define SOCK_DGRAM 2 12 | 13 | /* TODO: this probably changes per platform */ 14 | #define AF_UNIX 1 15 | #define AF_INET 2 16 | #define PF_INET AF_INET 17 | 18 | /* NOTE: this can differ on some architectures */ 19 | #define SOL_SOCKET 1 20 | 21 | /* NOTE: these can differ on some architectures */ 22 | #define SO_KEEPALIVE 9 23 | #define SO_SNDBUF 7 24 | 25 | int socket(int domain, int type, int protocol); 26 | 27 | int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 28 | int getsockopt(int socket, int level, int option_name, 29 | void *__zrestrict option_value, socklen_t *__zrestrict option_len); 30 | int setsockopt(int socket, int level, int option_name, 31 | const void *option_value, socklen_t option_len); 32 | 33 | int getpeername(int socket, struct sockaddr *__zrestrict address, 34 | socklen_t *__zrestrict address_len); 35 | int getsockname(int socket, struct sockaddr *__zrestrict address, 36 | socklen_t *__zrestrict address_len); 37 | 38 | int connect(int socket, const struct sockaddr *address, socklen_t address_len); 39 | ssize_t sendto(int socket, const void *message, size_t len, 40 | int flags, const struct sockaddr *dest_addr, 41 | socklen_t dest_len); 42 | ssize_t recv(int socket, void *buffer, size_t length, int flags); 43 | ssize_t recvfrom(int socket, void *__zrestrict buffer, size_t length, 44 | int flag, struct sockaddr *__zrestrict address, 45 | socklen_t *__zrestrict address_len); 46 | #define SHUT_RD 0 47 | #define SHUT_WR 1 48 | #define SHUT_RDWR 2 49 | int shutdown(int socket, int how); 50 | 51 | #endif /* _SYS_SOCKET_H */ 52 | -------------------------------------------------------------------------------- /inc/posix/sys/stat.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_STAT_H 2 | #define _SYS_STAT_H 3 | 4 | #include "../../libc/private/restrict.h" 5 | #include "../../libc/private/time_t.h" 6 | 7 | #include "../private/dev_t.h" 8 | #include "../private/ino_t.h" 9 | #include "../private/mode_t.h" 10 | #include "../private/nlink_t.h" 11 | #include "../private/uid_t.h" 12 | #include "../private/gid_t.h" 13 | #include "../private/off_t.h" 14 | #include "../private/blksize_t.h" 15 | #include "../private/blkcnt_t.h" 16 | 17 | #define S_IXUSR 0100 18 | #define S_IWUSR 0200 19 | #define S_IRUSR 0400 20 | #define S_IRWXG 0070 21 | #define S_IRWXO 0007 22 | 23 | struct stat { 24 | dev_t st_dev; 25 | ino_t st_ino; 26 | mode_t st_mode; 27 | nlink_t st_nlink; 28 | uid_t st_uid; 29 | gid_t st_gid; 30 | dev_t st_rdev; 31 | off_t st_size; 32 | time_t st_atime; 33 | time_t st_mtime; 34 | time_t st_ctime; 35 | blksize_t st_blksize; 36 | blkcnt_t st_blocks; 37 | }; 38 | 39 | int stat(const char *__zrestrict path, struct stat *__zrestrict buf); 40 | int chmod(const char *path, mode_t mode); 41 | int fstat(int fildes, struct stat *buf); 42 | mode_t umask(mode_t); 43 | 44 | #endif /* _SYS_STAT_H */ 45 | -------------------------------------------------------------------------------- /inc/posix/sys/time.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_TIME_H 2 | #define _SYS_TIME_H 3 | 4 | #include "../private/suseconds_t.h" 5 | #include "../private/fd_set.h" 6 | 7 | #include "../../libc/private/time_t.h" 8 | #include "../private/timeval.h" 9 | 10 | #define ITIMER_REAL 0 11 | #define ITIMER_VIRTUAL 1 12 | #define ITIMER_PROF 2 13 | 14 | struct itimerval { 15 | struct timeval it_interval; 16 | struct timeval it_value; 17 | }; 18 | 19 | int getitimer(int, struct itimerval *); 20 | int setitimer(int, const struct itimerval *, struct itimerval *); 21 | int gettimeofday(struct timeval *, void *); 22 | int select(int, fd_set *, fd_set *, fd_set *, struct timeval *); 23 | int utimes(const char *, const struct timeval [2]); 24 | 25 | #endif /* _SYS_TIME_H */ 26 | 27 | -------------------------------------------------------------------------------- /inc/posix/sys/types.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_TYPES_H 2 | #define _SYS_TYPES_H 3 | 4 | #include "../private/ssize_t.h" 5 | #include "../private/pid_t.h" 6 | #include "../private/uid_t.h" 7 | #include "../private/gid_t.h" 8 | #include "../private/mode_t.h" 9 | #include "../private/key_t.h" 10 | 11 | #endif /* _SYS_TYPES_H */ 12 | -------------------------------------------------------------------------------- /inc/posix/sys/uio.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_UIO_H 2 | #define _SYS_UIO_H 3 | 4 | #include "../../libc/private/size_t.h" 5 | #include "../private/ssize_t.h" 6 | 7 | struct iovec { 8 | void *iov_base; 9 | size_t iov_len; 10 | }; 11 | 12 | ssize_t readv(int, const struct iovec *, int); 13 | ssize_t writev(int, const struct iovec *, int); 14 | 15 | #endif /* _SYS_UIO_H */ 16 | -------------------------------------------------------------------------------- /inc/posix/sys/un.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_UN_H 2 | #define _SYS_UN_H 3 | 4 | #include "../private/sa_family_t.h" 5 | 6 | struct sockaddr_un { 7 | sa_family_t sun_family; 8 | char sun_path[108]; 9 | }; 10 | 11 | #endif /* _SYS_UN_H */ 12 | -------------------------------------------------------------------------------- /inc/posix/termios.h: -------------------------------------------------------------------------------- 1 | #ifndef _TERMIOS_H 2 | #define _TERMIOS_H 3 | 4 | typedef unsigned char cc_t; 5 | typedef unsigned tcflag_t; 6 | 7 | #define NCSS 32 8 | 9 | struct termios { 10 | tcflag_t c_iflag; 11 | tcflag_t c_oflag; 12 | tcflag_t c_cflag; 13 | tcflag_t c_lflag; 14 | cc_t c_cc[NCSS]; 15 | }; 16 | 17 | /* NOTE: these can change depending on platform */ 18 | 19 | #define VMIN 6 20 | #define VTIME 5 21 | 22 | /* Input Modes */ 23 | #define BRKINT 0x0002 24 | #define INPCK 0x0010 25 | #define ISTRIP 0x0020 26 | #define ICRNL 0x0100 27 | #define IXON 0x0400 28 | 29 | #define OPOST 0x0001 30 | 31 | #define CS8 0x0030 32 | 33 | /* Local Modes */ 34 | #define ISIG 0x0001 35 | #define ICANON 0x0002 36 | #define ECHO 0x0008 37 | #define IEXTEN 0x8000 38 | 39 | /* Attribute Selection */ 40 | #define TCSAFLUSH 2 41 | 42 | int tcgetattr(int, struct termios *); 43 | int tcsetattr(int fildes, int optional_actions, const struct termios *termios_p); 44 | 45 | /* I think these definitions are specific to linux but go in termios.h */ 46 | #if 1 47 | #define TIOCGWINSZ 0x5413 48 | struct winsize { 49 | unsigned short ws_row; 50 | unsigned short ws_col; 51 | unsigned short ws_xpixel; 52 | unsigned short ws_ypixel; 53 | }; 54 | #endif 55 | 56 | #endif /* _TERMIOS_H */ 57 | -------------------------------------------------------------------------------- /inc/posix/unistd.h: -------------------------------------------------------------------------------- 1 | #ifndef _UNISTD_H 2 | #define _UNISTD_H 3 | 4 | #include "../libc/private/size_t.h" 5 | #include "private/getopt.h" 6 | #include "private/ssize_t.h" 7 | #include "private/off_t.h" 8 | 9 | #define X_OK 1 10 | #define R_OK 4 11 | int access(const char *path, int amode); 12 | int close(int filedes); 13 | 14 | ssize_t read(int filedes, void *buf, size_t nbyte); 15 | ssize_t write(int fildes, const void *buf, size_t nbyte); 16 | 17 | #define _PC_LINK_MAX 0 18 | 19 | long fpathconf(int fileds, int name); 20 | long pathconf(const char *path, int name); 21 | 22 | int link(const char *path1, const char *path2); 23 | unsigned sleep(unsigned seconds); 24 | 25 | int unlink(const char *path); 26 | void _exit(int status); 27 | 28 | int gethostname(char *name, size_t namelen); 29 | int isatty(int filedes); 30 | 31 | //off_t lseek(int fildes, off_t offset, int whence); 32 | 33 | #endif /* _UNISTD_H */ 34 | -------------------------------------------------------------------------------- /inc/win32/basetcsd.h: -------------------------------------------------------------------------------- 1 | #ifndef _BASETSD_H 2 | #define _BASETSD_H 3 | 4 | #include "private/types.h" 5 | 6 | #endif /* _BASETSD_H */ 7 | -------------------------------------------------------------------------------- /inc/win32/errhandlingapi.h: -------------------------------------------------------------------------------- 1 | #ifndef _ERRHANDLINGAPI_H 2 | #define _ERRHANDLINGAPI_H 3 | 4 | #include "private/types.h" 5 | DWORD GetLastError(); 6 | 7 | #endif /* _ERRHANDLINGAPI_H */ 8 | -------------------------------------------------------------------------------- /inc/win32/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _IO_H 2 | #define _IO_H 3 | 4 | int _isatty(int fd); 5 | 6 | #endif /* _IO_H */ 7 | -------------------------------------------------------------------------------- /inc/win32/libloaderapi.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIBLOADERAPI_H 2 | #define _LIBLOADERAPI_H 3 | 4 | HMODULE LoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); 5 | BOOL FreeLibrary(HMODULE hLibModule); 6 | DWORD GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize); 7 | 8 | #endif /* _LIBLOADERAPI_H */ 9 | -------------------------------------------------------------------------------- /inc/win32/private/types.h: -------------------------------------------------------------------------------- 1 | #ifndef _WIN32_PRIVATE_TYPES_H 2 | #define _WIN32_PRIVATE_TYPES_H 3 | 4 | #include "../../libc/private/int32_t.h" 5 | 6 | #define _nullterminated 7 | 8 | typedef int BOOL; 9 | typedef void *PVOID; 10 | typedef const void *LPCVOID; 11 | typedef int32_t DWORD; 12 | typedef char CHAR; 13 | typedef CHAR *LPSTR; 14 | typedef _nullterminated const char *LPCSTR; 15 | typedef void *HMODULE; 16 | typedef PVOID HANDLE; 17 | 18 | #ifdef UNICODE 19 | typedef LPWSTR LPTSTR; 20 | #else 21 | typedef LPSTR LPTSTR; 22 | #endif 23 | 24 | #endif /* _WIN32_PRIVATE_TYPES_H */ 25 | -------------------------------------------------------------------------------- /inc/win32/winbase.h: -------------------------------------------------------------------------------- 1 | #ifndef _WINBASE_H 2 | #define _WINBASE_H 3 | 4 | DWORD FormatMessageA( 5 | DWORD dwFlags, 6 | LPCVOID lpSource, 7 | DWORD dwMessageId, 8 | DWORD dwLanguageId, 9 | LPTSTR lpBuffer, 10 | DWORD nSize, 11 | va_list *Arguments); 12 | 13 | #define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x00000100 14 | #define FORMAT_MESSAGE_ARGUMENT_ARRAY 0x00002000 15 | #define FORMAT_MESSAGE_FROM_HMODULE 0x00000800 16 | #define FORMAT_MESSAGE_FROM_STRING 0x00000400 17 | #define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000 18 | #define FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200 19 | #define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000 20 | 21 | #endif /* _WINBASE_H */ 22 | -------------------------------------------------------------------------------- /inc/win32/windef.h: -------------------------------------------------------------------------------- 1 | #ifndef _WINDEF_H 2 | #define _WINDEF_H 3 | 4 | #include "private/types.h" 5 | 6 | #endif /* _WINDEF_H */ 7 | -------------------------------------------------------------------------------- /inc/win32/windows.h: -------------------------------------------------------------------------------- 1 | #ifndef _WINDOWS_H 2 | #define _WINDOWS_H 3 | 4 | #include "private/types.h" 5 | 6 | #include "winbase.h" 7 | #include "errhandlingapi.h" 8 | #include "libloaderapi.h" 9 | 10 | #define MAX_PATH 260 11 | 12 | #endif /* _WINDOWS_H */ 13 | -------------------------------------------------------------------------------- /inc/win32/winnt.h: -------------------------------------------------------------------------------- 1 | #ifndef _WINNT_H 2 | #define _WINNT_H 3 | 4 | #include "private/types.h" 5 | 6 | #endif /* _WINNT_H */ 7 | -------------------------------------------------------------------------------- /luabuild.zig: -------------------------------------------------------------------------------- 1 | pub const core_objects = [_][]const u8{ 2 | "lapi", "lcode", "lctype", "ldebug", "ldo", "ldump", "lfunc", "lgc", "llex", 3 | "lmem", "lobject", "lopcodes", "lparser", "lstate", "lstring", "ltable", "ltm", "lundump", 4 | "lvm", "lzio", "ltests", 5 | }; 6 | pub const aux_objects = [_][]const u8{"lauxlib"}; 7 | pub const lib_objects = [_][]const u8{ 8 | "lbaselib", "ldblib", "liolib", "lmathlib", "loslib", "ltablib", "lstrlib", 9 | "lutf8lib", "loadlib", "lcorolib", "linit", 10 | }; 11 | -------------------------------------------------------------------------------- /ncurses/DEFS: -------------------------------------------------------------------------------- 1 | #define PACKAGE "ncurses" 2 | #define NCURSES_VERSION "6.3" 3 | #define NCURSES_PATCHDATE 20211021 4 | #define SYSTEM_NAME "linux-gnu" 5 | #if 0 6 | #include 7 | #endif 8 | #define HAVE_LONG_FILE_NAMES 1 9 | #define MIXEDCASE_FILENAMES 1 10 | #define TERMINFO_DIRS "/usr/share/terminfo" 11 | #define TERMINFO "/usr/share/terminfo" 12 | #define HAVE_BIG_CORE 1 13 | #define PURE_TERMINFO 1 14 | #define USE_HOME_TERMINFO 1 15 | #define USE_ROOT_ENVIRON 1 16 | #define USE_ROOT_ACCESS 1 17 | #define HAVE_UNISTD_H 1 18 | #define HAVE_REMOVE 1 19 | #define HAVE_UNLINK 1 20 | #define HAVE_LINK 1 21 | #define HAVE_SYMLINK 1 22 | #define USE_LINKS 1 23 | #define HAVE_LANGINFO_CODESET 1 24 | #define HAVE_FSEEKO 1 25 | #define RGB_PATH "/usr/share/X11/rgb.txt" 26 | #define STDC_HEADERS 1 27 | #define HAVE_SYS_TYPES_H 1 28 | #define HAVE_SYS_STAT_H 1 29 | #define HAVE_STDLIB_H 1 30 | #define HAVE_STRING_H 1 31 | #define HAVE_MEMORY_H 1 32 | #define HAVE_STRINGS_H 1 33 | #define HAVE_INTTYPES_H 1 34 | #define HAVE_STDINT_H 1 35 | #define HAVE_UNISTD_H 1 36 | #define SIZEOF_SIGNED_CHAR 1 37 | #define NCURSES_EXT_FUNCS 1 38 | #define HAVE_ASSUME_DEFAULT_COLORS 1 39 | #define HAVE_CURSES_VERSION 1 40 | #define HAVE_HAS_KEY 1 41 | #define HAVE_RESIZETERM 1 42 | #define HAVE_RESIZE_TERM 1 43 | #define HAVE_TERM_ENTRY_H 1 44 | #define HAVE_USE_DEFAULT_COLORS 1 45 | #define HAVE_USE_EXTENDED_NAMES 1 46 | #define HAVE_USE_SCREEN 1 47 | #define HAVE_USE_WINDOW 1 48 | #define HAVE_WRESIZE 1 49 | #define NCURSES_SP_FUNCS 1 50 | #define HAVE_TPUTS_SP 1 51 | #define NCURSES_EXT_PUTWIN 1 52 | #define NCURSES_NO_PADDING 1 53 | #define USE_SIGWINCH 1 54 | #define NCURSES_WRAP_PREFIX "_nc_" 55 | #define USE_ASSUMED_COLOR 1 56 | #define USE_HASHMAP 1 57 | #define GCC_SCANF 1 58 | #define GCC_SCANFLIKE(fmt,var) __attribute__((format(scanf,fmt,var))) 59 | #define GCC_PRINTF 1 60 | #define GCC_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var))) 61 | #define GCC_UNUSED __attribute__((unused)) 62 | #define GCC_NORETURN __attribute__((noreturn)) 63 | #define HAVE_NC_ALLOC_H 1 64 | #define HAVE_GETTIMEOFDAY 1 65 | #define STDC_HEADERS 1 66 | #define HAVE_DIRENT_H 1 67 | #define TIME_WITH_SYS_TIME 1 68 | #define HAVE_REGEX_H_FUNCS 1 69 | #define HAVE_FCNTL_H 1 70 | #define HAVE_GETOPT_H 1 71 | #define HAVE_LIMITS_H 1 72 | #define HAVE_LOCALE_H 1 73 | #define HAVE_MATH_H 1 74 | #define HAVE_POLL_H 1 75 | #define HAVE_SYS_IOCTL_H 1 76 | #define HAVE_SYS_PARAM_H 1 77 | #define HAVE_SYS_POLL_H 1 78 | #define HAVE_SYS_SELECT_H 1 79 | #define HAVE_SYS_TIME_H 1 80 | #define HAVE_SYS_TIMES_H 1 81 | #define HAVE_TTYENT_H 1 82 | #define HAVE_UNISTD_H 1 83 | #define HAVE_WCTYPE_H 1 84 | #define HAVE_UNISTD_H 1 85 | #define HAVE_GETOPT_H 1 86 | #define HAVE_GETOPT_HEADER 1 87 | #define DECL_ENVIRON 1 88 | #define HAVE_ENVIRON 1 89 | #define HAVE_PUTENV 1 90 | #define HAVE_SETENV 1 91 | #define HAVE_STRDUP 1 92 | #define HAVE_SYS_TIME_SELECT 1 93 | #define SIG_ATOMIC_T volatile sig_atomic_t 94 | #define HAVE_GETCWD 1 95 | #define HAVE_GETEGID 1 96 | #define HAVE_GETEUID 1 97 | #define HAVE_GETOPT 1 98 | #define HAVE_GETTTYNAM 1 99 | #define HAVE_LOCALECONV 1 100 | #define HAVE_POLL 1 101 | #define HAVE_PUTENV 1 102 | #define HAVE_REMOVE 1 103 | #define HAVE_SELECT 1 104 | #define HAVE_SETBUF 1 105 | #define HAVE_SETBUFFER 1 106 | #define HAVE_SETENV 1 107 | #define HAVE_SETFSUID 1 108 | #define HAVE_SETVBUF 1 109 | #define HAVE_SIGACTION 1 110 | #define HAVE_SNPRINTF 1 111 | #define HAVE_STRDUP 1 112 | #define HAVE_STRSTR 1 113 | #define HAVE_SYSCONF 1 114 | #define HAVE_TCGETPGRP 1 115 | #define HAVE_TIMES 1 116 | #define HAVE_TSEARCH 1 117 | #define HAVE_VSNPRINTF 1 118 | #define HAVE_ISASCII 1 119 | #define HAVE_NANOSLEEP 1 120 | #define HAVE_TERMIO_H 1 121 | #define HAVE_TERMIOS_H 1 122 | #define HAVE_UNISTD_H 1 123 | #define HAVE_SYS_IOCTL_H 1 124 | #define HAVE_TCGETATTR 1 125 | #define HAVE_VSSCANF 1 126 | #define HAVE_UNISTD_H 1 127 | #define HAVE_MKSTEMP 1 128 | #define HAVE_SIZECHANGE 1 129 | //#define HAVE_WORKING_POLL 1 130 | #define HAVE_VA_COPY 1 131 | #define HAVE_UNISTD_H 1 132 | #define HAVE_FORK 1 133 | #define HAVE_VFORK 1 134 | #define HAVE_WORKING_VFORK 1 135 | #define HAVE_WORKING_FORK 1 136 | #define USE_FOPEN_BIN_R 1 137 | #define USE_OPENPTY_HEADER 138 | #define USE_XTERM_PTY 1 139 | #define HAVE_TYPEINFO 1 140 | #define HAVE_IOSTREAM 1 141 | #define IOSTREAM_NAMESPACE 1 142 | #define SIZEOF_BOOL 1 143 | #define CPP_HAS_STATIC_CAST 1 144 | #define HAVE_SLK_COLOR 1 145 | #define HAVE_PANEL_H 1 146 | #define HAVE_LIBPANEL 1 147 | #define HAVE_MENU_H 1 148 | #define HAVE_LIBMENU 1 149 | #define HAVE_FORM_H 1 150 | #define HAVE_LIBFORM 1 151 | #define NCURSES_PATHSEP ':' 152 | #define NCURSES_VERSION_STRING "6.3.20211021" 153 | #define NCURSES_OSPEED_COMPAT 1 154 | #define HAVE_CURSES_DATA_BOOLNAMES 1 155 | -------------------------------------------------------------------------------- /ncurses/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const GitRepoStep = @import("../GitRepoStep.zig"); 3 | const ProcessFileStep = @import("../ProcessFileStep.zig"); 4 | const filecheck = @import("../filecheck.zig"); 5 | 6 | const NcursesPrepStep = struct { 7 | step: std.build.Step, 8 | builder: *std.build.Builder, 9 | repo_path: []const u8, 10 | 11 | defs_h_src: []const u8, 12 | defs_h_dst: []const u8, 13 | //curses_h: []const u8, 14 | 15 | pub fn create(b: *std.build.Builder, repo: *GitRepoStep) *NcursesPrepStep { 16 | var result = b.allocator.create(NcursesPrepStep) catch unreachable; 17 | result.* = NcursesPrepStep{ 18 | .step = std.build.Step.init(.{ 19 | .id = .custom, 20 | .name = "ncurses prep", 21 | .owner = b, 22 | .makeFn = make, 23 | }), 24 | .builder = b, 25 | .repo_path = repo.path, 26 | .defs_h_src = b.pathJoin(&.{ repo.path, "include", "ncurses_defs" }), 27 | .defs_h_dst = b.pathJoin(&.{ repo.path, "include", "ncurses_def.h" }), 28 | //.curses_h = b.pathJoin(&.{repo.path, "include", "curses.h"}), 29 | }; 30 | result.*.step.dependOn(&repo.step); 31 | return result; 32 | } 33 | fn make(step: *std.build.Step, progress: *std.Progress.Node) !void { 34 | _ = progress; 35 | const self = @fieldParentPtr(NcursesPrepStep, "step", step); 36 | //try self.generateCuresesH(); 37 | try self.generateNcursesDefH(); 38 | } 39 | 40 | //fn generateCursesH(self: NcursesPrepStep) !void { 41 | //} 42 | 43 | fn generateNcursesDefH(self: NcursesPrepStep) !void { 44 | // TODO: use bash on include/MKncurses_def.sh 45 | // they use awk, I don't think there's any reason we 46 | // couldn't use awk as well. We should be able to get awk 47 | // working on any platform/OS. 48 | if (try filecheck.leftFileIsNewer(self.defs_h_dst, self.defs_h_src)) 49 | return; 50 | var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); 51 | defer arena.deinit(); 52 | const content = std.fs.cwd().readFileAlloc(arena.allocator(), self.defs_h_src, std.math.maxInt(usize)) catch |err| { 53 | std.log.err("failed to read file '{s}' to process ({s})", .{ self.defs_h_src, @errorName(err) }); 54 | std.os.exit(0xff); 55 | }; 56 | 57 | const tmp_filename = try std.fmt.allocPrint(arena.allocator(), "{s}.processing", .{self.defs_h_dst}); 58 | { 59 | var out_file = try std.fs.cwd().createFile(tmp_filename, .{}); 60 | defer out_file.close(); 61 | 62 | const writer = out_file.writer(); 63 | try writer.writeAll("/* This file is generated by ncurses/build.zig */\n"); 64 | try writer.writeAll("#ifndef NC_DEFINE_H\n"); 65 | try writer.writeAll("#define NC_DEFINE_H\n"); 66 | 67 | var it = std.mem.split(u8, content, "\n"); 68 | while (it.next()) |line_untrimmed| { 69 | const line = std.mem.trim(u8, line_untrimmed, " \t\r"); 70 | if (line.len == 0 or line[0] == '#') continue; 71 | var field_it = std.mem.tokenize(u8, line, " \t"); 72 | const name = field_it.next().?; 73 | const optional_value = field_it.next(); 74 | try writer.print("\n#ifndef {s}\n", .{name}); 75 | if (optional_value) |value| { 76 | const value_offset = @intFromPtr(value.ptr) - @intFromPtr(line.ptr); 77 | try writer.print("#define {s} {s}\n", .{ name, line[value_offset..] }); 78 | } else { 79 | try writer.print("#define {s} 0\n", .{name}); 80 | } 81 | try writer.print("#endif\n", .{}); 82 | } 83 | try writer.writeAll("#endif /* NC_DEFINE_H */\n"); 84 | } 85 | try std.fs.cwd().rename(tmp_filename, self.defs_h_dst); 86 | } 87 | }; 88 | 89 | fn addProcessFile( 90 | b: *std.build.Builder, 91 | repo: *GitRepoStep, 92 | exe: *std.build.LibExeObjStep, 93 | in_sub_path: []const u8, 94 | out_sub_path: []const u8, 95 | opt: struct { 96 | subs: []const ProcessFileStep.Sub = &[_]ProcessFileStep.Sub{}, 97 | }, 98 | ) void { 99 | const process_file = ProcessFileStep.create(b, .{ 100 | .in_filename = b.pathJoin(&.{ repo.path, in_sub_path }), 101 | .out_filename = b.pathJoin(&.{ repo.path, out_sub_path }), 102 | .subs = opt.subs, 103 | }); 104 | process_file.step.dependOn(&repo.step); 105 | exe.step.dependOn(&process_file.step); 106 | } 107 | 108 | pub fn add( 109 | b: *std.build.Builder, 110 | target: anytype, 111 | optimize: anytype, 112 | libc_only_std_static: *std.build.LibExeObjStep, 113 | zig_posix: *std.build.LibExeObjStep, 114 | ) *std.build.LibExeObjStep { 115 | const repo = GitRepoStep.create(b, .{ 116 | .url = "https://github.com/mirror/ncurses", 117 | .sha = "deb0d07e8eb4803b9e9653359eab17a30d04369d", 118 | .branch = null, 119 | }); 120 | 121 | const prep = NcursesPrepStep.create(b, repo); 122 | 123 | const exe = b.addStaticLibrary(.{ 124 | .name = "ncurses", 125 | .target = target, 126 | .optimize = optimize, 127 | }); 128 | addProcessFile( 129 | b, 130 | repo, 131 | exe, 132 | b.pathJoin(&.{ "include", "ncurses_dll.h.in" }), 133 | b.pathJoin(&.{ "include", "ncurses_dll.h" }), 134 | .{}, 135 | ); 136 | 137 | const defs_sub = ProcessFileStep.Sub{ 138 | .current = "@DEFS@", 139 | .new = @embedFile("DEFS"), 140 | }; 141 | addProcessFile( 142 | b, 143 | repo, 144 | exe, 145 | b.pathJoin(&.{ "include", "ncurses_cfg.hin" }), 146 | b.pathJoin(&.{ "include", "ncurses_cfg.h" }), 147 | .{ .subs = &.{defs_sub} }, 148 | ); 149 | //addProcessFile(b, repo, exe, 150 | // b.pathJoin(&.{"include", "curses.h.in"}), 151 | // b.pathJoin(&.{"include", "curses.head"}), 152 | // .{ .subs = &.{ defs_sub } }, 153 | //); 154 | const install = b.addInstallArtifact(exe, .{}); 155 | exe.step.dependOn(&prep.step); 156 | const repo_path = repo.getPath(&exe.step); 157 | var files = std.ArrayList([]const u8).init(b.allocator); 158 | for ([_][]const u8{"lib_initscr.c"}) |src| { 159 | files.append(b.pathJoin(&.{ repo_path, "ncurses", "base", src })) catch unreachable; 160 | } 161 | exe.addCSourceFiles(files.toOwnedSlice() catch unreachable, &[_][]const u8{ 162 | "-std=c99", 163 | }); 164 | exe.addIncludePath(.{ .path = b.pathJoin(&.{ repo_path, "include" }) }); 165 | exe.addIncludePath(.{ .path = b.pathJoin(&.{ repo_path, "ncurses" }) }); 166 | 167 | exe.addIncludePath(.{ .path = "inc/libc" }); 168 | exe.addIncludePath(.{ .path = "inc/posix" }); 169 | exe.addIncludePath(.{ .path = "inc/linux" }); 170 | //exe.addIncludePath(.{.path = "inc/gnu"}); 171 | exe.linkLibrary(libc_only_std_static); 172 | //exe.linkLibrary(zig_start); 173 | exe.linkLibrary(zig_posix); 174 | //exe.linkLibrary(zig_gnu); 175 | // TODO: should libc_only_std_static and zig_start be able to add library dependencies? 176 | if (target.getOs().tag == .windows) { 177 | exe.linkSystemLibrary("ntdll"); 178 | exe.linkSystemLibrary("kernel32"); 179 | } 180 | 181 | const step = b.step("ncurses", "build the ncurses library"); 182 | step.dependOn(&install.step); 183 | 184 | return exe; 185 | } 186 | -------------------------------------------------------------------------------- /ncurses/gen-curses-h: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | set -eu 3 | if [ ! "$#" = "1" ]; then 4 | echo "Usage: gen-curses-h NCURSES_PATH" 5 | exit 1 6 | fi 7 | ncurses_path=$1 8 | inc=$ncurses_path/include 9 | out=inc/curses.h 10 | tmp=${out}.processing 11 | cat $inc/curses.head > $tmp 12 | $inc/MKkey_defs.h >> $tmp 13 | cat $inc/curses.tail >> $tmp 14 | -------------------------------------------------------------------------------- /src/genheaders.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); 4 | const arena = arena_instance.allocator(); 5 | 6 | pub fn main() !u8 { 7 | const all_args = try std.process.argsAlloc(arena); 8 | 9 | if (all_args.len <= 1) { 10 | std.debug.print("Usage: genheaders CAPI_TXT_FILE\n", .{}); 11 | return 0xff; 12 | } 13 | const args = all_args[1..]; 14 | if (args.len != 1) { 15 | std.log.err("expected 1 cmd-line argument but got {}", .{args.len}); 16 | return 0xff; 17 | } 18 | const capi_filename = args[0]; 19 | std.log.info("reading api from '{s}'...", .{capi_filename}); 20 | const contents = try std.fs.cwd().readFileAlloc(arena, capi_filename, std.math.maxInt(usize)); 21 | 22 | var parser = Parser.init(arena, capi_filename, contents); 23 | try parser.genHeaders(); 24 | if (parser.total_errors > 0) { 25 | std.log.err("{d} errors", .{parser.total_errors}); 26 | return 0xff; 27 | } 28 | 29 | for (parser.definitions.items) |def| { 30 | std.log.info("{}", .{def.def}); 31 | } 32 | 33 | return 0; 34 | } 35 | 36 | fn isWhitespace(c: u8) bool { 37 | return c == ' '; 38 | } 39 | 40 | fn skipWhitespace(text: []const u8, offset: usize) usize { 41 | var i = offset; 42 | while (i < text.len) : (i += 1) { 43 | if (!isWhitespace(text[i])) break; 44 | } 45 | return i; 46 | } 47 | fn toWhitespace(text: []const u8, offset: usize) usize { 48 | var i = offset; 49 | while (i < text.len) : (i += 1) { 50 | if (isWhitespace(text[i])) break; 51 | } 52 | return i; 53 | } 54 | 55 | fn peel(text: *[]const u8) ?[]const u8 { 56 | const start = skipWhitespace(text.*, 0); 57 | if (start == text.len) { 58 | text.* = text.*[start..]; 59 | return null; 60 | } 61 | const end = toWhitespace(text.*, start + 1); 62 | const result = text.*[start..end]; 63 | text.* = text.*[end..]; 64 | return result; 65 | } 66 | 67 | const ErrorReporter = struct { 68 | filename: []const u8, 69 | base_line_number: u32, 70 | count: u32, 71 | fn report(self: *ErrorReporter, line_offset: u32, comptime msg: []const u8, args: anytype) void { 72 | self.count += 1; 73 | std.log.err("{s}:{d} " ++ msg, .{ self.filename, self.base_line_number + line_offset } ++ args); 74 | } 75 | }; 76 | 77 | const ReportedError = error{Reported}; 78 | fn parseDefinition( 79 | allocator: std.mem.Allocator, 80 | error_reporter: *ErrorReporter, 81 | text: []const u8, 82 | ) !?*Definition { 83 | var line_it = std.mem.split(u8, text, "\n"); 84 | const first_line = line_it.next().?; 85 | if (!std.mem.eql(u8, first_line, "c89")) { 86 | std.debug.panic("first line not being 'c89', instead is '{s}', not implemented", .{first_line}); 87 | } 88 | var line_offset: u32 = 1; 89 | const def = blk: { 90 | const def_line_original = line_it.next() orelse { 91 | error_reporter.report(line_offset, "definition is missing it's second line", .{}); 92 | return ReportedError.Reported; 93 | }; 94 | var remaining_line = def_line_original; 95 | var abi_type = peel(&remaining_line) orelse { 96 | error_reporter.report(line_offset, "definition line is empty? '{s}'", .{def_line_original}); 97 | return ReportedError.Reported; 98 | }; 99 | if (std.mem.eql(u8, abi_type, "define")) { 100 | const name = peel(&remaining_line) orelse { 101 | error_reporter.report(line_offset, "'define' requires a name and value", .{}); 102 | return ReportedError.Reported; 103 | }; 104 | const value_start = skipWhitespace(remaining_line, 0); 105 | if (value_start == remaining_line.len) { 106 | error_reporter.report(line_offset, "'define {s}' has a name but missing a value", .{name}); 107 | return ReportedError.Reported; 108 | } 109 | const value = std.mem.trimRight(u8, remaining_line[value_start..], " "); 110 | const def = try allocator.create(Definition); 111 | def.* = .{ 112 | .headers = &[_][]const u8{}, 113 | .def = .{ .define = .{ 114 | .name = name, 115 | .value = value, 116 | } }, 117 | }; 118 | break :blk def; 119 | } else { 120 | error_reporter.report(line_offset, "unknown abi type '{s}'", .{abi_type}); 121 | return ReportedError.Reported; 122 | } 123 | }; 124 | 125 | var headers = std.ArrayListUnmanaged([]const u8){}; 126 | defer headers.deinit(allocator); 127 | while (true) { 128 | line_offset += 1; 129 | const line_original = line_it.next() orelse break; 130 | var remaining_line = line_original; 131 | var directive = peel(&remaining_line) orelse break; 132 | if (std.mem.eql(u8, directive, "header")) { 133 | const name = peel(&remaining_line) orelse { 134 | error_reporter.report(line_offset, "'header' requires a name", .{}); 135 | return ReportedError.Reported; 136 | }; 137 | if (peel(&remaining_line)) |_| { 138 | error_reporter.report(line_offset, "'header' got too many arguments", .{}); 139 | return ReportedError.Reported; 140 | } 141 | try headers.append(allocator, name); 142 | } else { 143 | error_reporter.report(line_offset, "unknown directive '{s}'", .{directive}); 144 | return ReportedError.Reported; 145 | } 146 | } 147 | def.*.headers = try headers.toOwnedSlice(allocator); 148 | return def; 149 | } 150 | 151 | const Parser = struct { 152 | allocator: std.mem.Allocator, 153 | filename: []const u8, 154 | contents: []const u8, 155 | definitions: std.ArrayListUnmanaged(*Definition), 156 | total_errors: u32 = 0, 157 | pub fn init(allocator: std.mem.Allocator, filename: []const u8, contents: []const u8) Parser { 158 | return .{ 159 | .allocator = allocator, 160 | .filename = filename, 161 | .contents = contents, 162 | .definitions = std.ArrayListUnmanaged(*Definition){}, 163 | }; 164 | } 165 | // TODO: deini? 166 | 167 | fn genHeaders(self: *Parser) !void { 168 | var started: ?struct { ptr: [*]const u8, line_number: u32 } = null; 169 | var line_it = std.mem.split(u8, self.contents, "\n"); 170 | var line_number: u32 = 0; 171 | 172 | while (line_it.next()) |line_untrimmed| { 173 | line_number += 1; 174 | // TODO: assert that line has no '\r\n'? 175 | const line = std.mem.trim(u8, line_untrimmed, " "); 176 | //std.log.info("line {d} '{s}'", .{line_number, line}); 177 | 178 | if (line.len == 0) { 179 | if (started) |info| { 180 | try self.addDefinition(info.line_number, info.ptr, line.ptr); 181 | started = null; 182 | } 183 | } else { 184 | if (started) |_| {} else { 185 | started = .{ .line_number = line_number, .ptr = line.ptr }; 186 | } 187 | } 188 | } 189 | if (started) |info| { 190 | try self.addDefinition(info.line_number, info.ptr, self.contents.ptr + self.contents.len); 191 | } 192 | } 193 | 194 | fn addDefinition(self: *Parser, line_number: u32, start: [*]const u8, limit: [*]const u8) !void { 195 | var error_reporter = ErrorReporter{ 196 | .filename = self.filename, 197 | .base_line_number = line_number, 198 | .count = 0, 199 | }; 200 | const text = start[0 .. @intFromPtr(limit) - @intFromPtr(start)]; 201 | if (try parseDefinition(self.allocator, &error_reporter, text)) |def| { 202 | std.debug.assert(error_reporter.count == 0); 203 | try self.definitions.append(self.allocator, def); 204 | } else { 205 | std.debug.assert(error_reporter.count > 0); 206 | self.total_errors += error_reporter.count; 207 | } 208 | } 209 | }; 210 | 211 | const Definition = struct { 212 | headers: []const []const u8, 213 | def: union(enum) { 214 | define: Define, 215 | type: Type, 216 | extern_var: ExternVar, 217 | function: Function, 218 | 219 | const Define = struct { 220 | name: []const u8, 221 | value: []const u8, 222 | }; 223 | 224 | const Type = union(enum) { 225 | builtin: struct { 226 | name: []const u8, 227 | }, 228 | typedef: struct { 229 | name: []const u8, 230 | definition: *const Type, 231 | }, 232 | opaque_struct: struct { 233 | name: []const u8, 234 | provide_size: bool, // I think the FILE is supposed to be opaque but gcc provides the size 235 | }, 236 | ptr: struct { 237 | target: *const Type, 238 | is_const: bool, 239 | }, 240 | }; 241 | 242 | const ExternVar = struct { 243 | name: []const u8, 244 | type: *const Type, 245 | }; 246 | 247 | const Param = struct { 248 | name: []const u8, 249 | type: *const Type, 250 | }; 251 | 252 | const Function = struct { 253 | name: []const u8, 254 | return_type: *const Type, 255 | params: []const Param, 256 | }; 257 | }, 258 | }; 259 | 260 | //const defs = [_]Definition { 261 | // Definition{ 262 | // .headers = &[_][]const u8 { 263 | // "stddef.h", // c89 264 | // "stdio.h", // c89 265 | // "stdlib.h", // c89 266 | // "string.h", // c89 267 | // "time.h", // c89 268 | // "locale.h", // c89 269 | // }, 270 | // .def = .{ .define = .{ .name = "NULL", .value = "((void*)0)" } }, 271 | // }, 272 | //}; 273 | // 274 | -------------------------------------------------------------------------------- /src/glibcstart.zig: -------------------------------------------------------------------------------- 1 | /// Symbols that we need to export if our library is to be used 2 | /// alongside the glibc start code (i.e. crtn.o, etc) 3 | const builtin = @import("builtin"); 4 | const std = @import("std"); 5 | 6 | const c = struct { 7 | extern fn main(argc: c_int, argv: [*:null]?[*:0]u8) callconv(.C) c_int; 8 | }; 9 | 10 | export fn __libc_csu_init( 11 | argc: c_int, 12 | argv: [*:null]?[*:0]u8, 13 | envp: [*:null]?[*:0]u8, 14 | ) callconv(.C) void { 15 | // do nothing for now 16 | _ = argc; 17 | _ = argv; 18 | _ = envp; 19 | } 20 | 21 | export fn __libc_csu_fini() callconv(.C) void { 22 | std.log.warn("called __libc_scu_fini", .{}); 23 | } 24 | 25 | export fn __libc_start_main( 26 | argc: c_int, 27 | argv: [*:null]?[*:0]u8, 28 | init: switch (builtin.zig_backend) { 29 | .stage1 => fn (argc: c_int, argv: [*:null]?[*:0]u8) callconv(.C) c_int, 30 | else => *const fn (argc: c_int, argv: [*:null]?[*:0]u8) callconv(.C) c_int, 31 | }, 32 | fini: fn () callconv(.C) void, 33 | rtld_fini: fn () callconv(.C) void, 34 | stack_end: *anyopaque, 35 | ) callconv(.C) noreturn { 36 | _ = init; 37 | _ = fini; 38 | _ = rtld_fini; 39 | _ = stack_end; 40 | std.log.warn("__libc_start_main is probably not doing everything it needs too", .{}); 41 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 42 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 43 | // TODO: pass envp 44 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 45 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 46 | var result = c.main(argc, argv); 47 | if (result != 0) { 48 | while ((result & 0xff == 0)) result = result >> 8; 49 | } 50 | std.os.exit(@as(u8, @intCast(result & 0xff))); 51 | } 52 | 53 | export fn __tls_get_addr(ptr: *usize) callconv(.C) *anyopaque { 54 | std.debug.panic("__tls_get_addr (ptr={*}) is not implemented", .{ptr}); 55 | } 56 | -------------------------------------------------------------------------------- /src/gnu.zig: -------------------------------------------------------------------------------- 1 | const c = @cImport({ 2 | @cInclude("argp.h"); 3 | }); 4 | 5 | export fn argp_usage(state: *const c.argp_state) callconv(.C) void { 6 | _ = state; 7 | @panic("argp_usage not implemented"); 8 | } 9 | 10 | export fn argp_parse( 11 | argp: *c.argp, 12 | argc: c_int, 13 | argv: [*:null]?[*:0]u8, 14 | flags: c_uint, 15 | arg_index: *c_int, 16 | input: *anyopaque, 17 | ) callconv(.C) c.error_t { 18 | _ = argp; 19 | _ = argc; 20 | _ = argv; 21 | _ = flags; 22 | _ = arg_index; 23 | _ = input; 24 | @panic("argp_parse not impl"); 25 | } 26 | -------------------------------------------------------------------------------- /src/lib.zig: -------------------------------------------------------------------------------- 1 | const modules = @import("modules"); 2 | comptime { 3 | if (modules.glibcstart) _ = @import("glibcstart.zig"); 4 | if (modules.cstd) _ = @import("cstd.zig"); 5 | if (modules.posix) _ = @import("posix.zig"); 6 | if (modules.linux) _ = @import("linux.zig"); 7 | if (modules.gnu) _ = @import("gnu.zig"); 8 | } 9 | -------------------------------------------------------------------------------- /src/linux.zig: -------------------------------------------------------------------------------- 1 | export fn alloca(size: usize) callconv(.C) [*]u8 { 2 | _ = size; 3 | @panic("alloca not implemented"); 4 | } 5 | -------------------------------------------------------------------------------- /src/linux/jmp.s: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license */ 2 | /* NOTE: this was copied from musl */ 3 | .global __setjmp 4 | .global _setjmp 5 | .global setjmp 6 | .type __setjmp,@function 7 | .type _setjmp,@function 8 | .type setjmp,@function 9 | __setjmp: 10 | _setjmp: 11 | setjmp: 12 | mov %rbx,(%rdi) /* rdi is jmp_buf, move registers onto it */ 13 | mov %rbp,8(%rdi) 14 | mov %r12,16(%rdi) 15 | mov %r13,24(%rdi) 16 | mov %r14,32(%rdi) 17 | mov %r15,40(%rdi) 18 | lea 8(%rsp),%rdx /* this is our rsp WITHOUT current ret addr */ 19 | mov %rdx,48(%rdi) 20 | mov (%rsp),%rdx /* save return addr ptr for new rip */ 21 | mov %rdx,56(%rdi) 22 | xor %eax,%eax /* always return 0 */ 23 | ret 24 | .global _longjmp 25 | .global longjmp 26 | .type _longjmp,@function 27 | .type longjmp,@function 28 | _longjmp: 29 | longjmp: 30 | xor %eax,%eax 31 | cmp $1,%esi /* CF = val ? 0 : 1 */ 32 | adc %esi,%eax /* eax = val + !val */ 33 | mov (%rdi),%rbx /* rdi is the jmp_buf, restore regs from it */ 34 | mov 8(%rdi),%rbp 35 | mov 16(%rdi),%r12 36 | mov 24(%rdi),%r13 37 | mov 32(%rdi),%r14 38 | mov 40(%rdi),%r15 39 | mov 48(%rdi),%rsp 40 | jmp *56(%rdi) /* goto saved address without altering rsp */ 41 | -------------------------------------------------------------------------------- /src/posix.c: -------------------------------------------------------------------------------- 1 | // NOTE: contains the implementations of functions for libposix 2 | // that require varargs 3 | #include 4 | #include 5 | #include 6 | 7 | // -------------------------------------------------------------------------------- 8 | // fcntl 9 | // -------------------------------------------------------------------------------- 10 | int open(const char *path, int oflag) 11 | { 12 | fprintf(stderr, "open function not implemented\n"); 13 | abort(); 14 | } 15 | 16 | // -------------------------------------------------------------------------------- 17 | // sys/ioctl 18 | // -------------------------------------------------------------------------------- 19 | int _ioctlArgPtr(int fd, unsigned long request, void *arg); 20 | 21 | int ioctl(int fd, unsigned long request, ...) 22 | { 23 | va_list args; 24 | va_start(args, request); 25 | void *arg_ptr = va_arg(args, void*); 26 | va_end(args); 27 | return _ioctlArgPtr(fd, request, arg_ptr); 28 | } 29 | -------------------------------------------------------------------------------- /src/posix.zig: -------------------------------------------------------------------------------- 1 | const builtin = @import("builtin"); 2 | const std = @import("std"); 3 | const os = std.os; 4 | 5 | const c = @cImport({ 6 | @cInclude("errno.h"); 7 | @cInclude("string.h"); 8 | @cInclude("stdlib.h"); 9 | @cInclude("stdio.h"); 10 | @cInclude("time.h"); 11 | @cInclude("signal.h"); 12 | @cInclude("termios.h"); 13 | @cInclude("sys/time.h"); 14 | @cInclude("sys/stat.h"); 15 | @cInclude("sys/select.h"); 16 | }); 17 | 18 | const cstd = struct { 19 | extern fn __zreserveFile() callconv(.C) ?*c.FILE; 20 | }; 21 | 22 | const trace = @import("trace.zig"); 23 | 24 | const global = struct { 25 | export var optarg: [*:0]u8 = undefined; 26 | export var opterr: c_int = undefined; 27 | export var optind: c_int = 1; 28 | export var optopt: c_int = undefined; 29 | }; 30 | 31 | /// Returns some information through these globals 32 | /// extern char *optarg; 33 | /// extern int opterr, optind, optopt; 34 | export fn getopt(argc: c_int, argv: [*][*:0]u8, optstring: [*:0]const u8) callconv(.C) c_int { 35 | trace.log("getopt argc={} argv={*} opstring={} (err={}, ind={}, opt={})", .{ 36 | argc, 37 | argv, 38 | trace.fmtStr(optstring), 39 | global.opterr, 40 | global.optind, 41 | global.optopt, 42 | }); 43 | if (global.optind >= argc) { 44 | trace.log("getopt return -1", .{}); 45 | return -1; 46 | } 47 | const arg = argv[@as(usize, @intCast(global.optind))]; 48 | if (arg[0] != '-') { 49 | // TODO: not sure if this is what we're supposed to do 50 | // my guess is we have to take this non-option 51 | // argument and move it to the front of argv, 52 | // then move on to the rest of the arguments to 53 | // check for more options 54 | if (global.optind + 1 != argc) { 55 | @panic("TODO: check the rest of the arguments"); 56 | } 57 | return -1; 58 | } 59 | 60 | global.optind += 1; 61 | if (arg[2] != 0) @panic("multi-letter argument not implemented"); 62 | const result = c.strchr(optstring, arg[1]) orelse { 63 | // I think we return '?' 64 | std.debug.panic("unknown option '{}', probably return '?'", .{arg[1]}); 65 | }; 66 | const takes_arg = result[1] == ':'; 67 | if (takes_arg) { 68 | const is_optional = result[2] == ':'; 69 | if (is_optional) @panic("optional args not implemented"); 70 | global.optarg = argv[@as(usize, @intCast(global.optind))]; 71 | if (global.optind >= argc or global.optarg[0] == '-') { 72 | std.debug.panic("TODO: handle missing arg for option '{}", .{arg[1]}); 73 | } 74 | global.optind += 1; 75 | } 76 | return @as(c_int, arg[1]); 77 | } 78 | 79 | export fn write(fd: c_int, buf: [*]const u8, nbyte: usize) callconv(.C) isize { 80 | if (builtin.os.tag == .windows) { 81 | @panic("write not implemented on windows"); 82 | } 83 | const rc = os.system.write(fd, buf, nbyte); 84 | switch (os.errno(rc)) { 85 | .SUCCESS => return @as(isize, @intCast(rc)), 86 | else => |e| { 87 | c.errno = @intFromEnum(e); 88 | return -1; 89 | }, 90 | } 91 | } 92 | 93 | export fn read(fd: c_int, buf: [*]u8, len: usize) callconv(.C) isize { 94 | trace.log("read fd={} buf={*} len={}", .{ fd, buf, len }); 95 | const rc = os.linux.read(fd, buf, len); 96 | switch (os.errno(rc)) { 97 | .SUCCESS => return @as(isize, @intCast(rc)), 98 | else => |e| { 99 | c.errno = @intFromEnum(e); 100 | return -1; 101 | }, 102 | } 103 | } 104 | 105 | // -------------------------------------------------------------------------------- 106 | // string 107 | // -------------------------------------------------------------------------------- 108 | export fn strdup(s: [*:0]const u8) callconv(.C) ?[*:0]u8 { 109 | trace.log("strdup '{}'", .{trace.fmtStr(s)}); 110 | const len = c.strlen(s); 111 | const optional_new_s = @as(?[*]u8, @ptrCast(c.malloc(len + 1))); 112 | if (optional_new_s) |new_s| { 113 | _ = c.strcpy(new_s, s); 114 | } 115 | return @as([*:0]u8, @ptrCast(optional_new_s)); // TODO: use std.meta.assumeSentinel if it's brought back 116 | } 117 | 118 | // -------------------------------------------------------------------------------- 119 | // stdlib 120 | // -------------------------------------------------------------------------------- 121 | export fn mkstemp(template: [*:0]u8) callconv(.C) c_int { 122 | return mkostemp(template, 0, 0); 123 | } 124 | 125 | export fn mkostemp(template: [*:0]u8, suffixlen: c_int, flags: c_int) callconv(.C) c_int { 126 | trace.log("mkstemp '{}'", .{trace.fmtStr(template)}); 127 | if (builtin.os.tag == .windows) { 128 | @panic("mkostemp not implemented in Windows"); 129 | } 130 | 131 | const rand_part: *[6]u8 = blk: { 132 | const len = c.strlen(template); 133 | if (6 + suffixlen > len) { 134 | c.errno = c.EINVAL; 135 | return -1; 136 | } 137 | const rand_part_off = len - @as(usize, @intCast(suffixlen)) - 6; 138 | break :blk @as(*[6]u8, @ptrCast(template + rand_part_off)); 139 | }; 140 | 141 | if (!std.mem.eql(u8, rand_part, "XXXXXX")) { 142 | c.errno = c.EINVAL; 143 | return -1; 144 | } 145 | 146 | const max_attempts = 200; 147 | var attempt: u32 = 0; 148 | while (true) : (attempt += 1) { 149 | randomizeTempFilename(rand_part); 150 | const fd = os.system.open(template, @as(u32, @intCast(flags | os.O.RDWR | os.O.CREAT | os.O.EXCL)), 0o600); 151 | switch (os.errno(fd)) { 152 | .SUCCESS => return @as(c_int, @intCast(fd)), 153 | else => |e| { 154 | if (attempt >= max_attempts) { 155 | // TODO: should we restore rand_part back to XXXXXX? 156 | c.errno = @intFromEnum(e); 157 | return -1; 158 | } 159 | }, 160 | } 161 | } 162 | } 163 | 164 | const filename_char_set = 165 | "+,-.0123456789=@ABCDEFGHIJKLMNOPQRSTUVWXYZ" ++ 166 | "_abcdefghijklmnopqrstuvwxyz"; 167 | fn randToFilenameChar(r: u8) u8 { 168 | return filename_char_set[r % filename_char_set.len]; 169 | } 170 | 171 | fn randomizeTempFilename(slice: *[6]u8) void { 172 | var randoms: [6]u8 = undefined; 173 | { 174 | const timestamp = std.time.nanoTimestamp(); 175 | var prng = std.rand.DefaultPrng.init(@as(u64, @intCast(std.math.maxInt(u64) & timestamp))); 176 | prng.random().bytes(&randoms); 177 | } 178 | var i: usize = 0; 179 | while (i < slice.len) : (i += 1) { 180 | slice[i] = randToFilenameChar(randoms[i]); 181 | } 182 | } 183 | 184 | // -------------------------------------------------------------------------------- 185 | // stdio 186 | // -------------------------------------------------------------------------------- 187 | export fn fileno(stream: *c.FILE) callconv(.C) c_int { 188 | if (builtin.os.tag == .windows) { 189 | // this probably isn't right, but might be fine for an initial implementation 190 | return @as(c_int, @intCast(@intFromPtr(stream.fd))); 191 | } 192 | @panic("fileno not implemented"); 193 | } 194 | 195 | export fn popen(command: [*:0]const u8, mode: [*:0]const u8) callconv(.C) *c.FILE { 196 | trace.log("popen '{}' mode='{s}'", .{ trace.fmtStr(command), mode }); 197 | @panic("popen not implemented"); 198 | } 199 | export fn pclose(stream: *c.FILE) callconv(.C) c_int { 200 | _ = stream; 201 | @panic("pclose not implemented"); 202 | } 203 | 204 | export fn fdopen(fd: c_int, mode: [*:0]const u8) callconv(.C) ?*c.FILE { 205 | trace.log("fdopen {d} mode={s}", .{ fd, mode }); 206 | if (builtin.os.tag == .windows) @panic("not impl"); 207 | 208 | const file = cstd.__zreserveFile() orelse { 209 | c.errno = c.ENOMEM; 210 | return null; 211 | }; 212 | file.fd = fd; 213 | file.eof = 0; 214 | return file; 215 | } 216 | 217 | // -------------------------------------------------------------------------------- 218 | // unistd 219 | // -------------------------------------------------------------------------------- 220 | comptime { 221 | if (builtin.os.tag != .windows) @export(close, .{ .name = "close" }); 222 | } 223 | fn close(fd: c_int) callconv(.C) c_int { 224 | trace.log("close {}", .{fd}); 225 | std.os.close(fd); 226 | return 0; 227 | } 228 | 229 | export fn access(path: [*:0]const u8, amode: c_int) callconv(.C) c_int { 230 | trace.log("access '{}' mode=0x{x}", .{ trace.fmtStr(path), amode }); 231 | @panic("acces not implemented"); 232 | } 233 | 234 | export fn unlink(path: [*:0]const u8) callconv(.C) c_int { 235 | if (builtin.os.tag == .windows) 236 | @panic("windows unlink not implemented"); 237 | 238 | switch (os.errno(os.system.unlink(path))) { 239 | .SUCCESS => return 0, 240 | else => |e| { 241 | c.errno = @intFromEnum(e); 242 | return -1; 243 | }, 244 | } 245 | } 246 | 247 | export fn _exit(status: c_int) callconv(.C) noreturn { 248 | if (builtin.os.tag == .windows) { 249 | os.windows.kernel32.ExitProcess(@as(c_uint, @bitCast(status))); 250 | } 251 | if (builtin.os.tag == .wasi) { 252 | os.wasi.proc_exit(status); 253 | } 254 | if (builtin.os.tag == .linux and !builtin.single_threaded) { 255 | // TODO: is this right? 256 | os.linux.exit_group(status); 257 | } 258 | os.system.exit(status); 259 | } 260 | 261 | export fn isatty(fd: c_int) callconv(.C) c_int { 262 | if (builtin.os.tag == .windows) 263 | @panic("isatty not supported on windows (yet?)"); 264 | 265 | var size: c.winsize = undefined; 266 | switch (os.errno(os.system.ioctl(fd, c.TIOCGWINSZ, @intFromPtr(&size)))) { 267 | .SUCCESS => return 1, 268 | .BADF => { 269 | c.errno = c.ENOTTY; 270 | return 0; 271 | }, 272 | else => return 0, 273 | } 274 | } 275 | 276 | // -------------------------------------------------------------------------------- 277 | // sys/time 278 | // -------------------------------------------------------------------------------- 279 | comptime { 280 | std.debug.assert(@sizeOf(c.timespec) == @sizeOf(os.timespec)); 281 | if (builtin.os.tag != .windows) { 282 | std.debug.assert(c.CLOCK_REALTIME == os.CLOCK.REALTIME); 283 | } 284 | } 285 | 286 | export fn clock_gettime(clk_id: c.clockid_t, tp: *os.timespec) callconv(.C) c_int { 287 | if (builtin.os.tag == .windows) { 288 | if (clk_id == c.CLOCK_REALTIME) { 289 | var ft: os.windows.FILETIME = undefined; 290 | os.windows.kernel32.GetSystemTimeAsFileTime(&ft); 291 | // FileTime has a granularity of 100 nanoseconds and uses the NTFS/Windows epoch. 292 | const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime; 293 | const ft_per_s = std.time.ns_per_s / 100; 294 | tp.* = .{ 295 | .tv_sec = @as(i64, @intCast(ft64 / ft_per_s)) + std.time.epoch.windows, 296 | .tv_nsec = @as(c_long, @intCast(ft64 % ft_per_s)) * 100, 297 | }; 298 | return 0; 299 | } 300 | // TODO POSIX implementation of CLOCK.MONOTONIC on Windows. 301 | std.debug.panic("clk_id {} not implemented on Windows", .{clk_id}); 302 | } 303 | 304 | switch (os.errno(os.system.clock_gettime(clk_id, tp))) { 305 | .SUCCESS => return 0, 306 | else => |e| { 307 | c.errno = @intFromEnum(e); 308 | return -1; 309 | }, 310 | } 311 | } 312 | 313 | export fn gettimeofday(tv: *c.timeval, tz: *anyopaque) callconv(.C) c_int { 314 | trace.log("gettimeofday tv={*} tz={*}", .{ tv, tz }); 315 | @panic("gettimeofday not implemented"); 316 | } 317 | 318 | export fn setitimer(which: c_int, value: *const c.itimerval, avalue: *c.itimerval) callconv(.C) c_int { 319 | trace.log("setitimer which={}", .{which}); 320 | _ = value; 321 | _ = avalue; 322 | @panic("setitimer not implemented"); 323 | } 324 | 325 | // -------------------------------------------------------------------------------- 326 | // signal 327 | // -------------------------------------------------------------------------------- 328 | export fn sigaction(sig: c_int, act: *const c.struct_sigaction, oact: *c.struct_sigaction) callconv(.C) c_int { 329 | trace.log("sigaction sig={}", .{sig}); 330 | _ = act; 331 | _ = oact; 332 | @panic("sigaction not implemented"); 333 | } 334 | 335 | // -------------------------------------------------------------------------------- 336 | // sys/stat.h 337 | // -------------------------------------------------------------------------------- 338 | export fn chmod(path: [*:0]const u8, mode: c.mode_t) callconv(.C) c_int { 339 | trace.log("chmod '{s}' mode=0x{x}", .{ path, mode }); 340 | @panic("chmod not implemented"); 341 | } 342 | 343 | export fn fstat(fd: c_int, buf: *c.struct_stat) c_int { 344 | _ = fd; 345 | _ = buf; 346 | @panic("fstat not implemented"); 347 | } 348 | 349 | export fn umask(mode: c.mode_t) callconv(.C) c.mode_t { 350 | trace.log("umask 0x{x}", .{mode}); 351 | const old_mode = os.linux.syscall1(.umask, @as(usize, @intCast(mode))); 352 | switch (os.errno(old_mode)) { 353 | .SUCCESS => {}, 354 | else => |e| std.debug.panic("umask syscall should never fail but got '{s}'", .{@tagName(e)}), 355 | } 356 | return @as(c.mode_t, @intCast(old_mode)); 357 | } 358 | 359 | // -------------------------------------------------------------------------------- 360 | // libgen 361 | // -------------------------------------------------------------------------------- 362 | export fn basename(path: ?[*:0]u8) callconv(.C) [*:0]u8 { 363 | trace.log("basename {}", .{trace.fmtStr(path)}); 364 | const path_slice = std.mem.span(path orelse return @as([*:0]u8, @ptrFromInt(@intFromPtr(".")))); 365 | const name = std.fs.path.basename(path_slice); 366 | const mut_ptr = @as([*:0]u8, @ptrFromInt(@intFromPtr(name.ptr))); 367 | if (name.len == 0) { 368 | if (path_slice.ptr[0] == '/') { 369 | path_slice.ptr[1] = 0; 370 | return path_slice.ptr; 371 | } 372 | return @as([*:0]u8, @ptrFromInt(@intFromPtr("."))); 373 | } 374 | if (mut_ptr[name.len] != 0) mut_ptr[name.len] = 0; 375 | return mut_ptr; 376 | } 377 | 378 | // -------------------------------------------------------------------------------- 379 | // termios 380 | // -------------------------------------------------------------------------------- 381 | export fn tcgetattr(fd: c_int, ios: *os.linux.termios) callconv(.C) c_int { 382 | switch (os.errno(os.linux.tcgetattr(fd, ios))) { 383 | .SUCCESS => return 0, 384 | else => |errno| { 385 | c.errno = @intFromEnum(errno); 386 | return -1; 387 | }, 388 | } 389 | } 390 | 391 | export fn tcsetattr( 392 | fd: c_int, 393 | optional_actions: c_int, 394 | ios: *const os.linux.termios, 395 | ) callconv(.C) c_int { 396 | switch (os.errno(os.linux.tcsetattr(fd, @as(os.linux.TCSA, @enumFromInt(optional_actions)), ios))) { 397 | .SUCCESS => return 0, 398 | else => |errno| { 399 | c.errno = @intFromEnum(errno); 400 | return -1; 401 | }, 402 | } 403 | } 404 | 405 | // -------------------------------------------------------------------------------- 406 | // strings 407 | // -------------------------------------------------------------------------------- 408 | export fn strcasecmp(a: [*:0]const u8, b: [*:0]const u8) callconv(.C) c_int { 409 | trace.log("strcasecmp {} {}", .{ trace.fmtStr(a), trace.fmtStr(b) }); 410 | @panic("not impl"); 411 | // var a_next = a; 412 | // var b_next = b; 413 | // while (a_next[0] == b_next[0] and a_next[0] != 0) { 414 | // a_next += 1; 415 | // b_next += 1; 416 | // } 417 | // const result = @intCast(c_int, a_next[0]) -| @intCast(c_int, b_next[0]); 418 | // trace.log("strcmp return {}", .{result}); 419 | // return result; 420 | } 421 | 422 | // -------------------------------------------------------------------------------- 423 | // sys/ioctl 424 | // -------------------------------------------------------------------------------- 425 | export fn _ioctlArgPtr(fd: c_int, request: c_ulong, arg_ptr: *anyopaque) c_int { 426 | trace.log("ioctl fd={} request=0x{x} arg={*}", .{ fd, request, arg_ptr }); 427 | const rc = os.linux.ioctl(fd, @as(u32, @intCast(request)), @intFromPtr(arg_ptr)); 428 | switch (os.errno(rc)) { 429 | .SUCCESS => return @as(c_int, @intCast(rc)), 430 | else => |errno| { 431 | c.errno = @intFromEnum(errno); 432 | return -1; 433 | }, 434 | } 435 | } 436 | 437 | // -------------------------------------------------------------------------------- 438 | // sys/select 439 | // -------------------------------------------------------------------------------- 440 | export fn select( 441 | nfds: c_int, 442 | readfds: ?*c.fd_set, 443 | writefds: ?*c.fd_set, 444 | errorfds: ?*c.fd_set, 445 | timeout: ?*c.timespec, 446 | ) c_int { 447 | _ = nfds; 448 | _ = readfds; 449 | _ = writefds; 450 | _ = errorfds; 451 | _ = timeout; 452 | @panic("TODO: implement select"); 453 | } 454 | 455 | // -------------------------------------------------------------------------------- 456 | // Windows 457 | // -------------------------------------------------------------------------------- 458 | comptime { 459 | if (builtin.os.tag == .windows) { 460 | @export(fileno, .{ .name = "_fileno" }); 461 | @export(isatty, .{ .name = "_isatty" }); 462 | @export(popen, .{ .name = "_popen" }); 463 | @export(pclose, .{ .name = "_pclose" }); 464 | } 465 | } 466 | -------------------------------------------------------------------------------- /src/printf.c: -------------------------------------------------------------------------------- 1 | // Some of ziglibc is currently in C to have vararg support 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // TODO: restrict pointers? 11 | size_t _fwrite_buf(const char *ptr, size_t size, FILE *stream); 12 | size_t _formatCInt(char *buf, int value, uint8_t base); 13 | size_t _formatCUint(char *buf, unsigned value, uint8_t base); 14 | size_t _formatCLong(char *buf, long value, uint8_t base); 15 | size_t _formatCUlong(char *buf, unsigned long value, uint8_t base); 16 | size_t _formatCLonglong(char *buf, long long value, uint8_t base); 17 | size_t _formatCUlonglong(char *buf, unsigned long long value, uint8_t base); 18 | 19 | static size_t stringPrintLen(const char *s, unsigned precision) { 20 | size_t len = 0; 21 | for (; s[len] && len < (size_t)precision; len++) { } 22 | return len; 23 | } 24 | 25 | struct Writer { 26 | // if len is 0, then s is null-terminated 27 | // returns the total number of bytes written 28 | // if the number of bytes written is less than len (or strlen(s)) 29 | // then errno should be set 30 | size_t (*write)(struct Writer *writer, const char *s, size_t len); 31 | }; 32 | 33 | // returns: 0 on success 34 | static int vformat(size_t *out_written, struct Writer *writer, const char *fmt, va_list args) { 35 | *out_written = 0; 36 | 37 | while (1) { 38 | const char *next_percent_char = strchr(fmt, '%'); 39 | if (next_percent_char == NULL) break; 40 | 41 | { 42 | size_t len = next_percent_char - fmt; 43 | if (len > 0) { 44 | size_t written = writer->write(writer, fmt, len); 45 | *out_written += written; 46 | if (written != len) { 47 | return -1; // error 48 | } 49 | } 50 | } 51 | fmt = next_percent_char + 1; 52 | 53 | // TODO: parse flags 54 | if (fmt[0] == '-' || fmt[0] == '+' || fmt[0] == ' ' || fmt[0] == '#' || fmt[0] == '0') { 55 | fprintf(stderr, "error: vformat flag '%c' is not implemented\n", fmt[0]); 56 | return -1; 57 | } 58 | 59 | // TODO: parse width 60 | if (fmt[0] == '*') { 61 | //width = va_arg(args, int); 62 | //fmt++; 63 | fprintf(stderr, "error: vformat number width '*' not implemented\n"); 64 | return -1; 65 | } else if (fmt[0] >= '0' && fmt[0] <= '9') { 66 | fprintf(stderr, "error: vformat number width not implemented\n"); 67 | return -1; 68 | } 69 | 70 | static const int PRECISION_NONE = -1; 71 | int precision = PRECISION_NONE; 72 | if (fmt[0] == '.') { 73 | fmt++; 74 | if (fmt[0] == '*') { 75 | precision = va_arg(args, int); 76 | fmt++; 77 | } else if (fmt[0] >= '0' && fmt[0] <= '9') { 78 | fprintf(stderr, "error: vformat precision number '%c' not implemented\n", fmt[0]); 79 | return -1; 80 | } else { 81 | // TODO: don't actually print an error message like this 82 | // TODO: set errno 83 | fprintf(stderr, "error: invalid precision specifier : .%s\n", fmt); 84 | return -1; 85 | } 86 | } 87 | 88 | static const unsigned char SPEC_LENGTH_NONE = 0; 89 | static const unsigned char SPEC_LENGTH_LONG = 1; 90 | static const unsigned char SPEC_LENGTH_LONG_LONG = 2; 91 | unsigned char spec_length = SPEC_LENGTH_NONE; 92 | if (fmt[0] == 'l') { 93 | if (fmt[1] == 'l') { 94 | spec_length = SPEC_LENGTH_LONG_LONG; 95 | fmt += 2; 96 | } else { 97 | spec_length = SPEC_LENGTH_LONG; 98 | fmt++; 99 | } 100 | } 101 | 102 | if (fmt[0] == 's') { 103 | if (spec_length != SPEC_LENGTH_NONE) { 104 | fprintf(stderr, "error: non-default length not implemented for 's' specifier\n"); 105 | return -1; 106 | } 107 | const char *s = va_arg(args, const char *); 108 | // TODO: is this how we should be handling NULL string pointers? 109 | if (s == NULL) s = "(null)"; 110 | 111 | size_t written = writer->write(writer, s, (precision == PRECISION_NONE) ? 0 : stringPrintLen(s, precision)); 112 | *out_written += written; 113 | // sanity check 114 | if ( (precision == PRECISION_NONE) && (s[written] != 0) ) return -1; // error 115 | fmt++; 116 | } else if (fmt[0] == 'c') { 117 | if (spec_length != SPEC_LENGTH_NONE) { 118 | fprintf(stderr, "error: non-default length not implemented for 'c' specifier\n"); 119 | return -1; 120 | } 121 | if (precision != PRECISION_NONE) { 122 | fprintf(stderr, "error: precision not implemented for 'c' specifier\n"); 123 | return -1; 124 | } 125 | char c = va_arg(args, int); 126 | size_t written = writer->write(writer, &c, 1); 127 | if (written != 1) return -1; 128 | *out_written += 1; 129 | fmt++; 130 | } else if (fmt[0] == 'd') { 131 | if (precision != PRECISION_NONE) { 132 | fprintf(stderr, "error: precision not implemented for 'd' specifier\n"); 133 | return -1; 134 | } 135 | char buf[100]; 136 | size_t format_len; 137 | if (spec_length == SPEC_LENGTH_NONE) { 138 | const int value = va_arg(args, int); 139 | format_len = _formatCInt(buf, value, 10); 140 | } else if (spec_length == SPEC_LENGTH_LONG) { 141 | const long int value = va_arg(args, long int); 142 | format_len = _formatCLong(buf, value, 10); 143 | } else if (spec_length == SPEC_LENGTH_LONG_LONG) { 144 | const long int value = va_arg(args, long long int); 145 | format_len = _formatCLonglong(buf, value, 10); 146 | } else abort(); 147 | size_t written = writer->write(writer, buf, format_len); 148 | *out_written += written; 149 | if (written != format_len) return -1; // error 150 | fmt++; 151 | } else if (fmt[0] == 'u' || fmt[0] == 'x') { 152 | uint8_t base = (fmt[0] == 'd') ? 10 : 16; 153 | if (precision != PRECISION_NONE) { 154 | fprintf(stderr, "error: precision not implemented for '%c' specifier\n", fmt[0]); 155 | return -1; 156 | } 157 | char buf[100]; 158 | size_t format_len; 159 | if (spec_length == SPEC_LENGTH_NONE) { 160 | const unsigned value = va_arg(args, unsigned); 161 | format_len = _formatCUint(buf, value, base); 162 | } else if (spec_length == SPEC_LENGTH_LONG) { 163 | const long unsigned value = va_arg(args, long unsigned); 164 | format_len = _formatCUlong(buf, value, base); 165 | } else if (spec_length == SPEC_LENGTH_LONG_LONG) { 166 | const long unsigned value = va_arg(args, long long unsigned); 167 | format_len = _formatCUlonglong(buf, value, base); 168 | } else abort(); 169 | 170 | size_t written = writer->write(writer, buf, format_len); 171 | *out_written += written; 172 | if (written != format_len) return -1; // error 173 | fmt++; 174 | } else if (fmt[0] == 0) { 175 | return -1; // spurious trailing '%' 176 | } else { 177 | fprintf(stderr, "error: vformat specifer not implemented: '%s'\n", fmt-1); 178 | return -1; 179 | } 180 | } 181 | if (fmt[0] != 0) { 182 | size_t written = writer->write(writer, fmt, 0); 183 | *out_written += written; 184 | if (fmt[written] != 0) { 185 | return -1; // error 186 | } 187 | } 188 | 189 | return 0; 190 | } 191 | 192 | struct StreamWriter { 193 | struct Writer base; 194 | FILE *stream; 195 | }; 196 | static size_t streamWrite(struct Writer *base, const char *s, size_t len) 197 | { 198 | struct StreamWriter *writer = (struct StreamWriter*)base; 199 | if (len == 0) len = strlen(s); 200 | return _fwrite_buf(s, len, writer->stream); 201 | } 202 | 203 | // TODO: restrict pointers? 204 | int vfprintf(FILE *stream, const char *format, va_list arg) 205 | { 206 | struct StreamWriter writer; 207 | writer.base.write = streamWrite; 208 | writer.stream = stream; 209 | size_t written; 210 | if (0 == vformat(&written, &writer.base, format, arg)) { 211 | return (int)written; 212 | } 213 | stream->errno = errno; 214 | return -1; 215 | } 216 | 217 | int vprintf(const char *format, va_list arg) 218 | { 219 | return vfprintf(stdout, format, arg); 220 | } 221 | 222 | // TODO: restrict pointers? 223 | int fprintf(FILE *stream, const char *format, ...) 224 | { 225 | va_list args; 226 | va_start(args, format); 227 | int result = vfprintf(stream, format, args); 228 | va_end(args); 229 | return result; 230 | } 231 | 232 | int printf(const char *format, ...) 233 | { 234 | va_list args; 235 | va_start(args, format); 236 | int result = vfprintf(stdout, format, args); 237 | va_end(args); 238 | return result; 239 | } 240 | 241 | struct BoundedBufferWriter { 242 | struct Writer base; 243 | char *buf; 244 | size_t len; 245 | char overflow; 246 | }; 247 | static size_t boundedBufferWrite(struct Writer *base, const char *s, size_t len) 248 | { 249 | struct BoundedBufferWriter *writer = (struct BoundedBufferWriter*)base; 250 | if (len == 0) len = strlen(s); 251 | 252 | if (!writer->overflow) { 253 | if (len > writer->len) { 254 | // no need to copy more data 255 | writer->overflow = 1; 256 | } else { 257 | memcpy(writer->buf, s, len); 258 | writer->buf += len; 259 | writer->len -= len; 260 | } 261 | } 262 | return len; 263 | } 264 | 265 | int vsnprintf(char * restrict s, size_t n, const char * restrict format, va_list args) 266 | { 267 | struct BoundedBufferWriter writer; 268 | writer.base.write = boundedBufferWrite; 269 | writer.buf = s; 270 | writer.len = n; 271 | writer.overflow = 0; 272 | size_t written; 273 | int result = vformat(&written, &writer.base, format, args); 274 | assert(result == 0); // vformat can't fail with BoundedBufferWriter 275 | if (written < n) { 276 | s[written] = 0; 277 | } 278 | return (int)written; 279 | } 280 | 281 | int snprintf(char * restrict s, size_t n, const char * restrict format, ...) 282 | { 283 | va_list args; 284 | va_start(args, format); 285 | int result = vsnprintf(s, n, format, args); 286 | va_end(args); 287 | return result; 288 | } 289 | 290 | struct UnboundedBufferWriter { 291 | struct Writer base; 292 | char *buf; 293 | }; 294 | static size_t unboundedBufferWrite(struct Writer *base, const char *s, size_t len) 295 | { 296 | struct UnboundedBufferWriter *writer = (struct UnboundedBufferWriter*)base; 297 | // TODO: probably should use strncpy if len is 0, could be faster 298 | if (len == 0) len = strlen(s); 299 | memcpy(writer->buf, s, len); 300 | writer->buf += len; 301 | return len; 302 | } 303 | 304 | int vsprintf(char * restrict s, const char * restrict format, va_list args) 305 | { 306 | struct UnboundedBufferWriter writer; 307 | writer.base.write = unboundedBufferWrite; 308 | writer.buf = s; 309 | size_t written; 310 | int result = vformat(&written, &writer.base, format, args); 311 | assert(result == 0); // vformat can't fail with BufferWriter 312 | s[written] = 0; 313 | return (int)written; 314 | } 315 | 316 | int sprintf(char *s, const char * restrict format, ...) 317 | { 318 | va_list args; 319 | va_start(args, format); 320 | int result = vsprintf(s, format, args); 321 | va_end(args); 322 | return result; 323 | } 324 | -------------------------------------------------------------------------------- /src/scanf.c: -------------------------------------------------------------------------------- 1 | // Some of ziglibc is currently in C to have vararg support 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | struct Reader { 12 | // This is a dumb/slow interface, improve this 13 | char (*read)(struct Reader *reader); 14 | }; 15 | 16 | enum ScanKind { 17 | SCAN_KIND_END, 18 | SCAN_KIND_TOKEN, 19 | SCAN_KIND_STRING, 20 | SCAN_KIND_HEX, 21 | SCAN_KIND_ERROR, 22 | }; 23 | 24 | enum Mod { 25 | MOD_NONE, 26 | MOD_LONG, 27 | }; 28 | 29 | struct IntStore { 30 | enum Mod mod; 31 | union { 32 | int i; 33 | long int li; 34 | }; 35 | }; 36 | static struct IntStore int_store_init(enum Mod mod, int val) { 37 | struct IntStore store; 38 | store.mod = mod; 39 | switch (mod) { 40 | case MOD_NONE: store.i = val; break; 41 | case MOD_LONG: store.li = (long int)val; break; 42 | default: assert(0); 43 | } 44 | return store; 45 | } 46 | static void int_store_mult_eq(struct IntStore *store, int mult) { 47 | switch (store->mod) { 48 | case MOD_NONE: store->i *= mult; break; 49 | case MOD_LONG: store->li *= (long int)mult; break; 50 | default: assert(0); 51 | } 52 | } 53 | static void int_store_plus_eq(struct IntStore *store, int plus) { 54 | switch (store->mod) { 55 | case MOD_NONE: store->i += plus; break; 56 | case MOD_LONG: store->li += (long int)plus; break; 57 | default: assert(0); 58 | } 59 | } 60 | 61 | struct Scan { 62 | enum ScanKind kind; 63 | union { 64 | struct { 65 | const char *start; 66 | const char *limit; 67 | } token; 68 | struct { 69 | int width; 70 | } string; 71 | struct { 72 | enum Mod mod; 73 | } hex; 74 | }; 75 | }; 76 | static struct Scan create_scan_end() { 77 | struct Scan scan; 78 | scan.kind = SCAN_KIND_END; 79 | return scan; 80 | } 81 | static struct Scan create_scan_token(const char *start, const char *limit) { 82 | struct Scan scan; 83 | scan.kind = SCAN_KIND_TOKEN; 84 | scan.token.start = start; 85 | scan.token.limit = limit; 86 | return scan; 87 | } 88 | static struct Scan create_scan_string(int width) { 89 | struct Scan scan; 90 | scan.kind = SCAN_KIND_STRING; 91 | scan.string.width = width; 92 | return scan; 93 | } 94 | static struct Scan create_scan_hex(enum Mod mod) { 95 | struct Scan scan; 96 | scan.kind = SCAN_KIND_HEX; 97 | scan.hex.mod = mod; 98 | return scan; 99 | } 100 | static struct Scan create_scan_error() { 101 | struct Scan scan; 102 | scan.kind = SCAN_KIND_ERROR; 103 | return scan; 104 | } 105 | 106 | static int parse_width(const char **fmt) 107 | { 108 | { 109 | char c = (*fmt)[0]; 110 | if (c > '9' || c < '1') 111 | return -1; 112 | } 113 | 114 | const char *start = (*fmt); 115 | int width = start[0] - '0'; 116 | while (1) { 117 | *fmt += 1; 118 | char c = (*fmt)[0]; 119 | if (c > '9' || c < '0') break; 120 | width *= 10; 121 | width += (int)(c - '0'); 122 | } 123 | 124 | return width; 125 | } 126 | 127 | static int hex_value(char c) { 128 | if (c < '0') return -1; 129 | if (c <= '9') return c - '0'; 130 | if (c < 'A') return -1; 131 | if (c <= 'F') return c - 'A' + 10; 132 | if (c < 'a') return -1; 133 | if (c <= 'f') return c - 'a' + 10; 134 | return -1; 135 | } 136 | 137 | static struct Scan get_next_scan(const char **fmt) { 138 | for (; isspace((*fmt)[0]); *fmt += 1) { } 139 | 140 | char first_c = (*fmt)[0]; 141 | if (first_c == '%' || first_c == '=') { 142 | *fmt += 1; 143 | 144 | enum Mod mod = MOD_NONE; 145 | if ((*fmt)[0] == 'l') { 146 | *fmt += 1; 147 | if ((*fmt)[1] == 'l') { 148 | *fmt += 1; 149 | fprintf(stderr, "scanf ll modifier not implemented\n"); 150 | abort(); 151 | } else { 152 | mod = MOD_LONG; 153 | } 154 | } 155 | 156 | int width = parse_width(fmt); 157 | char c = (*fmt)[0]; 158 | if (c == 's') { 159 | *fmt += 1; 160 | if (mod != MOD_NONE) { 161 | fprintf(stderr, "scanf modifier for specifier 's' is not implemented\n"); 162 | abort(); 163 | } 164 | return create_scan_string(width); 165 | } else if (c == 'x' || c == 'X') { 166 | *fmt += 1; 167 | if (width != -1) { 168 | fprintf(stderr, "scanf width for hex specifier is not implemented\n"); 169 | abort(); 170 | } 171 | return create_scan_hex(mod); 172 | } else { 173 | fprintf(stderr, "scanf modifier or specifier '%c' is invalid or not implemented\n", c); 174 | abort(); 175 | } 176 | 177 | } else if (first_c == 0) { 178 | return create_scan_end(); 179 | } else { 180 | const char *start = (*fmt); 181 | while (1) { 182 | *fmt += 1; 183 | char c = (*fmt)[0]; 184 | if (c == 0 || c == '%' || c == '=' || isspace(c)) break; 185 | } 186 | return create_scan_token(start, *fmt); 187 | } 188 | } 189 | 190 | // returns: the number of arguments scanned, EOF on error 191 | static int vscanf(struct Reader *reader, const char *fmt, va_list args) { 192 | const char *fmt_start = fmt; 193 | int scan_count = 0; 194 | 195 | while (1) { 196 | struct Scan scan = get_next_scan(&fmt); 197 | switch (scan.kind) { 198 | case SCAN_KIND_END: 199 | return scan_count; 200 | case SCAN_KIND_TOKEN: { 201 | char c; 202 | do { c = reader->read(reader); } while (isspace(c)); 203 | 204 | const char *next = scan.token.start; 205 | while (1) { 206 | if (next[0] != c) return (scan_count == 0) ? -1 : scan_count; 207 | next++; 208 | if (next >= scan.token.limit) break; 209 | c = reader->read(reader); 210 | } 211 | break; 212 | } 213 | case SCAN_KIND_STRING: { 214 | char c; 215 | do { c = reader->read(reader); } while (isspace(c)); 216 | 217 | char *s_arg = va_arg(args, char *); 218 | int total_read = 0; 219 | while (c != 0) { 220 | s_arg[total_read] = c; 221 | total_read++; 222 | if (scan.string.width != -1 && total_read >= scan.string.width) break; 223 | c = reader->read(reader); 224 | if (isspace(c)) break; 225 | } 226 | if (total_read == 0) return (scan_count == 0) ? -1 : scan_count; 227 | if (total_read != 0) { 228 | s_arg[total_read] = 0; 229 | } 230 | scan_count++; 231 | break; 232 | } 233 | case SCAN_KIND_HEX: { 234 | char c; 235 | do { c = reader->read(reader); } while (isspace(c)); 236 | 237 | struct IntStore store = int_store_init(scan.hex.mod, 0); 238 | int read_at_least_one = 0; 239 | while (1) { 240 | int val = hex_value(c); 241 | if (val == -1) break; 242 | read_at_least_one = 1; 243 | int_store_mult_eq(&store, 16); 244 | int_store_plus_eq(&store, val); 245 | c = reader->read(reader); 246 | } 247 | if (!read_at_least_one) return (scan_count == 0) ? -1 : scan_count; 248 | switch (store.mod) { 249 | case MOD_NONE: *va_arg(args, int*) = store.i; break; 250 | case MOD_LONG: *va_arg(args, long int*) = store.li; break; 251 | default: assert(0); 252 | } 253 | scan_count++; 254 | break; 255 | } 256 | case SCAN_KIND_ERROR: 257 | return -1; 258 | default: 259 | fprintf(stderr, "codebug: unhandled scan kind %d\n", scan.kind); 260 | abort(); 261 | } 262 | } 263 | } 264 | 265 | struct FixedReader { 266 | struct Reader base; 267 | const char *buf; 268 | }; 269 | char fixedReaderRead(struct Reader *base) { 270 | struct FixedReader *reader = (struct FixedReader*)base; 271 | const char c = reader->buf[0]; 272 | if (c) { 273 | reader->buf += 1; 274 | } 275 | return c; 276 | } 277 | 278 | int sscanf(const char *s, const char *fmt, ...) { 279 | struct FixedReader reader; 280 | reader.base.read = fixedReaderRead; 281 | reader.buf = s; 282 | va_list args; 283 | va_start(args, fmt); 284 | int result = vscanf(&reader.base, fmt, args); 285 | va_end(args); 286 | return result; 287 | } 288 | -------------------------------------------------------------------------------- /src/start.zig: -------------------------------------------------------------------------------- 1 | const builtin = @import("builtin"); 2 | const std = @import("std"); 3 | 4 | const c = struct { 5 | extern fn main(argc: c_int, argv: [*:null]?[*:0]u8) callconv(.C) c_int; 6 | }; 7 | 8 | pub fn main() u8 { 9 | var argc: c_int = undefined; 10 | const args: [*:null]?[*:0]u8 = blk: { 11 | if (builtin.os.tag == .windows) { 12 | const args = windowsArgsAlloc(); 13 | argc = @intCast(args.len); 14 | break :blk args.ptr; 15 | } 16 | argc = @as(c_int, @intCast(std.os.argv.len)); 17 | break :blk @as([*:null]?[*:0]u8, @ptrCast(std.os.argv.ptr)); 18 | }; 19 | 20 | var result = c.main(argc, args); 21 | if (result != 0) { 22 | while ((result & 0xff == 0)) result = result >> 8; 23 | } 24 | return @as(u8, @intCast(result & 0xff)); 25 | } 26 | 27 | // TODO: I'm pretty sure this could be more memory efficient 28 | fn windowsArgsAlloc() [:null]?[*:0]u8 { 29 | const out_of_memory_msg = "Out Of Memory while decoding command line"; 30 | 31 | var argv_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); 32 | var tmp_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); 33 | defer tmp_arena.deinit(); 34 | 35 | var argv = std.ArrayListUnmanaged(?[*:0]u8){}; 36 | var it = std.process.argsWithAllocator(tmp_arena.allocator()) catch |err| switch (err) { 37 | error.OutOfMemory => @panic(out_of_memory_msg), 38 | // TODO: would be nice to get the actual utf16 decode error name 39 | error.InvalidCmdLine => @panic("Failed to decode command line"), 40 | }; 41 | defer it.deinit(); 42 | while (it.next()) |tmp_arg| { 43 | const arg = argv_arena.allocator().dupeZ(u8, tmp_arg) catch @panic(out_of_memory_msg); 44 | argv.append(argv_arena.allocator(), arg) catch @panic(out_of_memory_msg); 45 | } 46 | return argv.toOwnedSliceSentinel(argv_arena.allocator(), null) catch @panic(out_of_memory_msg); 47 | } 48 | -------------------------------------------------------------------------------- /src/trace.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const trace_options = @import("trace_options"); 3 | 4 | pub fn log(comptime fmt: []const u8, args: anytype) void { 5 | if (trace_options.enabled) { 6 | std.log.scoped(.trace).info(fmt, args); 7 | } 8 | } 9 | 10 | pub fn fmtStr(s: anytype) FmtStr { 11 | switch (@typeInfo(@TypeOf(s))) { 12 | .Pointer => |info| switch (info.size) { 13 | .Slice => return FmtStr.initSlice(s), 14 | .Many => if (info.sentinel) |_| { 15 | return FmtStr.initSentinel(s); 16 | }, 17 | else => {}, 18 | }, 19 | .Optional => return fmtStr(s orelse return FmtStr.initNull()), 20 | else => {}, 21 | } 22 | @compileError("fmtStr for type " ++ @typeName(@TypeOf(s)) ++ " is not implemented"); 23 | } 24 | const FmtStr = struct { 25 | const max_str_len = 26; 26 | 27 | ptr_opt: ?[*]const u8, 28 | len: union(enum) { 29 | full: u8, 30 | truncated: void, 31 | }, 32 | 33 | pub fn initNull() FmtStr { 34 | return .{ .ptr_opt = null, .len = undefined }; 35 | } 36 | pub fn initSlice(s: []const u8) FmtStr { 37 | if (s.len > max_str_len) { 38 | return .{ .ptr_opt = s.ptr, .len = .truncated }; 39 | } 40 | return .{ .ptr_opt = s.ptr, .len = .{ .len = @as(u8, s.len) } }; 41 | } 42 | 43 | pub fn initSentinel(s: [*:0]const u8) FmtStr { 44 | var len: u8 = 0; 45 | while (len <= max_str_len) : (len += 1) { 46 | if (s[len] == 0) 47 | return .{ .ptr_opt = s, .len = .{ .full = len } }; 48 | } 49 | return .{ .ptr_opt = s, .len = .truncated }; 50 | } 51 | 52 | pub fn format( 53 | self: @This(), 54 | comptime fmt: []const u8, 55 | options: std.fmt.FormatOptions, 56 | writer: anytype, 57 | ) @TypeOf(writer).Error!void { 58 | _ = fmt; 59 | _ = options; 60 | const ptr = self.ptr_opt orelse { 61 | try writer.writeAll("NULL"); 62 | return; 63 | }; 64 | const part: struct { s_len: u8, suffix: []const u8 } = switch (self.len) { 65 | .full => |len| .{ .s_len = len, .suffix = "" }, 66 | .truncated => .{ .s_len = max_str_len - 3, .suffix = "..." }, 67 | }; 68 | try writer.print("{*} \"{}\"{s}", .{ ptr, std.zig.fmtEscapes(ptr[0..part.s_len]), part.suffix }); 69 | } 70 | }; 71 | -------------------------------------------------------------------------------- /test/expect.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void on_expect_fail(const char *expression, const char *file, int line, const char *func) 5 | { 6 | fprintf(stderr, "%s:%d: expect failure '%s' in function '%s'\n", file, line, expression, func); 7 | exit(0xff); 8 | } 9 | -------------------------------------------------------------------------------- /test/expect.h: -------------------------------------------------------------------------------- 1 | #define expect(expr) ((void)((expr) || (on_expect_fail(#expr, __FILE__, __LINE__, __func__),0))) 2 | 3 | // TODO: mark on_expect_fail as noreturn 4 | void on_expect_fail(const char *expression, const char *file, int line, const char *func); 5 | -------------------------------------------------------------------------------- /test/format.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "expect.h" 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | char buffer[200]; 9 | expect (13 == snprintf(buffer, sizeof(buffer), "Hello %s\n", "World!")); 10 | expect(0 == strcmp(buffer, "Hello World!\n")); 11 | expect(13 == snprintf(buffer, 0, "Hello %s\n", "World!")); 12 | 13 | expect(18 == snprintf(buffer, sizeof(buffer), "Hello number %d\n", 1293)); 14 | expect(0 == strcmp(buffer, "Hello number 1293\n")); 15 | expect(20 == snprintf(buffer, sizeof(buffer), "Hello number 0x%x\n", 0x1fa2)); 16 | expect(0 == strcmp(buffer, "Hello number 0x1fa2\n")); 17 | 18 | expect(4 == snprintf(buffer, sizeof(buffer), "%s", "abcd")); 19 | expect(0 == strcmp(buffer, "abcd")); 20 | expect(3 == snprintf(buffer, sizeof(buffer), "%.*s", 3, "abcd")); 21 | expect(0 == strcmp(buffer, "abc")); 22 | 23 | printf("Success!\n"); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /test/fs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "expect.h" 5 | 6 | // CWD should be a directory available to create files 7 | int main(int argc, char *argv[]) 8 | { 9 | const char *filename = "foo"; 10 | FILE *file = fopen(filename, "w"); 11 | // NOT WORKING YET! 12 | //if (file == NULL) { 13 | // fprintf(stderr, "error: fopen '%s' failed, errno=%d\n", filename, errno); 14 | // return 1; 15 | //} 16 | //expect(0 == fclose(file)); 17 | printf("Success!\n"); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /test/getopt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | int aflag = 0; 8 | char *c_arg = NULL; 9 | { 10 | int c; 11 | while ((c = getopt(argc, argv, "abc:")) != -1) { 12 | switch (c) { 13 | case 'a': 14 | aflag = 1; 15 | break; 16 | case 'c': 17 | c_arg = optarg; 18 | break; 19 | case '?': 20 | fprintf(stderr, "Unrecognized option: '-%c'\n", optopt); 21 | return 1; 22 | default: 23 | assert(0); 24 | } 25 | } 26 | } 27 | printf("aflag=%d, c_arg='%s'\n", aflag, c_arg); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /test/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | // NOTE: passing NULL to puts is undefined behavior 6 | //puts(0); 7 | if (EOF == puts("Hello")) { 8 | return -1; 9 | } 10 | return 0; 11 | //printf("Hello\n"); 12 | } 13 | -------------------------------------------------------------------------------- /test/jmp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void do_longjmp(jmp_buf env, int val) 5 | { 6 | //fprintf(stderr, "longjmp val=%d\n", val); 7 | longjmp(env, val); 8 | } 9 | 10 | int main(int argc, char *argv[]) 11 | { 12 | jmp_buf env; 13 | int result = setjmp(env); 14 | //fprintf(stderr, "setjmp returned %d\n", result); 15 | if (result == 0) { 16 | do_longjmp(env, 1); 17 | } else if (result == 1) { 18 | printf("Success!\n"); 19 | return 0; 20 | } 21 | fprintf(stderr, "should never get here\n"); 22 | return 0xff; 23 | } 24 | -------------------------------------------------------------------------------- /test/scanf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "expect.h" 7 | 8 | #define test(expected_return, expected_errno, str, fmt, ...) do { \ 9 | errno = 0; \ 10 | expect(expected_return == sscanf(str, fmt, ##__VA_ARGS__)); \ 11 | expect(expected_errno == errno); \ 12 | } while (0) 13 | 14 | int main(int argc, char *argv[]) 15 | { 16 | int i; 17 | long int li; 18 | char buf_3[3]; 19 | 20 | test(0, 0, "abc", "abc"); 21 | //test(-1, EINVAL, "abc", "abc%0s", buf); 22 | 23 | test(-1, 0, "abc", "abc%2s", buf_3); 24 | test(1, 0, "abcd", "abc%2s", buf_3); 25 | expect(0 == strcmp("d", buf_3)); 26 | test(1, 0, "abc d", "abc%2s", buf_3); 27 | expect(0 == strcmp("d", buf_3)); 28 | test(1, 0, "abcde", "abc%2s", buf_3); 29 | expect(0 == strcmp("de", buf_3)); 30 | test(1, 0, "abcdef", "abc%2s", buf_3); 31 | expect(0 == strcmp("de", buf_3)); 32 | 33 | test(1, 0, "123af0", "%x", &i); 34 | expect(0x123af0 == i); 35 | test(1, 0, " 123af0", "%x", &i); 36 | expect(0x123af0 == i); 37 | test(1, 0, "f019", "%lx", &li); 38 | expect(0xf019 == li); 39 | 40 | test(1, 0, "a bc", "a %2s", buf_3); 41 | test(1, 0, "a a402", "a %lx", &li); 42 | expect(0xa402 == li); 43 | test(1, 0, "a b c9f2", "a b %lx", &li); 44 | expect(0xc9f2 == li); 45 | test(1, 0, "a bd594", "a b%lx", &li); 46 | expect(0xd594 == li); 47 | test(2, 0, "a bc 0x820", "a %2s 0x%lx", buf_3, &li); 48 | expect(0 == strcmp("bc", buf_3)); 49 | expect(0x820 == li); 50 | 51 | puts("Success!"); 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /test/strings.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "expect.h" 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | expect(16 == strlen("this is a string")); 10 | 11 | expect(0 == strcmp("abc", "abc")); 12 | expect(0 > strcmp("abc", "abd")); 13 | expect(0 < strcmp("abd", "abc")); 14 | 15 | expect(0 == strncmp("abc", "abc", 3)); 16 | expect(0 == strncmp("abc", "abc", 2)); 17 | expect(0 == strncmp("abc", "abd", 2)); 18 | expect(0 > strncmp("abc", "abd", 3)); 19 | expect(0 == strncmp("abd", "abc", 2)); 20 | expect(0 < strncmp("abd", "abc", 3)); 21 | 22 | expect(NULL == strchr("hello", 'z')); 23 | { 24 | const char *s = "abcdef"; 25 | expect(s + 4 == strchr(s, 'e')); 26 | } 27 | 28 | { 29 | const char *s = "abcdef"; 30 | expect(s+1 == strstr(s, "bcde")); 31 | expect(NULL == strstr(s, "bcdeg")); 32 | } 33 | 34 | puts("Success!"); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /test/strto.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "expect.h" 8 | 9 | static void test_l(const char *str, int base, int expected_errno, size_t parse_len, long expected) 10 | { 11 | char *endptr; 12 | errno = 0; 13 | expect(expected == strtol(str, &endptr, base)); 14 | expect(errno == expected_errno); 15 | expect(endptr == str + parse_len); 16 | } 17 | static void test_ul(const char *str, int base, int expected_errno, size_t parse_len, unsigned long expected) 18 | { 19 | char *endptr; 20 | errno = 0; 21 | expect(expected == strtoul(str, &endptr, base)); 22 | expect(errno == expected_errno); 23 | expect(endptr == str + parse_len); 24 | } 25 | 26 | int main(int argc, char *argv[]) 27 | { 28 | test_l("2147483647", 0, 0, 10, 2147483647L); 29 | test_ul("4294967295", 0, 0, 10, 4294967295UL); 30 | 31 | test_l("z", 36, 0, 1, 35); 32 | test_l("00010010001101000101011001111000", 2, 0, 32, 0x12345678); 33 | test_l("0F5F", 16, 0, 4, 0xf5f); 34 | 35 | //test_l("0xz", 16, EINVAL, 2, 0); 36 | 37 | test_l("0x1234", 16, 0, 6, 0x1234); 38 | 39 | test_l("123", 37, EINVAL, 0, 0); 40 | 41 | test_l(" 15437", 8, 0, 7, 015437); 42 | test_l(" 1", 0, 0, 3, 1); 43 | 44 | puts("Success!"); 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /test/testenv.zig: -------------------------------------------------------------------------------- 1 | /// Run the given program in a clean directory 2 | const std = @import("std"); 3 | 4 | var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); 5 | 6 | pub fn main() !u8 { 7 | const full_args = try std.process.argsAlloc(arena.allocator()); 8 | if (full_args.len <= 1) { 9 | try std.io.getStdErr().writer().writeAll("Usage: testenv PROGRAM ARGS...\n"); 10 | return 1; 11 | } 12 | const args = full_args[1..]; 13 | 14 | // TODO: improve this 15 | const dirname = try std.fmt.allocPrint(arena.allocator(), "{s}.test.tmp", .{std.fs.path.basename(args[0])}); 16 | try std.fs.cwd().deleteTree(dirname); 17 | try std.fs.cwd().makeDir(dirname); 18 | var child = std.ChildProcess.init(args, arena.allocator()); 19 | child.cwd = dirname; 20 | try child.spawn(); 21 | const result = try child.wait(); 22 | switch (result) { 23 | .Exited => |code| { 24 | if (code != 0) return code; 25 | }, 26 | else => |r| { 27 | std.log.err("child process failed with {}", .{r}); 28 | return 0xff; 29 | }, 30 | } 31 | try std.fs.cwd().deleteTree(dirname); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /test/types.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | argc--; argv++; 12 | if (argc != 1) { 13 | fprintf(stderr, "expected 1 cmd-line arg but got %d\n", argc); 14 | return -1; 15 | } 16 | char *ptr_width_str = argv[0]; 17 | unsigned ptr_width; 18 | if (0 == strcmp(ptr_width_str, "4")) { 19 | ptr_width = 4; 20 | } else if (0 == strcmp(ptr_width_str, "8")) { 21 | ptr_width = 8; 22 | } else { 23 | fprintf(stderr, "unknown ptr width '%s'\n", ptr_width_str); 24 | return -1; 25 | } 26 | 27 | int result = 0; 28 | 29 | #define fail(msg, ...) do { \ 30 | result = -1; \ 31 | fprintf(stderr, msg "\n", ##__VA_ARGS__); \ 32 | } while(0) 33 | 34 | #define check_equal(prefix, fmt_spec, expected, actual) \ 35 | if (expected != actual) { \ 36 | result = -1; \ 37 | fprintf(stderr, prefix " expected " fmt_spec " but got " fmt_spec "\n", expected, actual); \ 38 | } 39 | 40 | #define check_sizeof(T,b) \ 41 | if (sizeof(T) != b) { \ 42 | result = -1; \ 43 | fprintf(stderr, #T " %u != %u\n", (unsigned)sizeof(T), b); \ 44 | } 45 | 46 | check_sizeof(size_t, ptr_width); 47 | check_sizeof(ssize_t, ptr_width); 48 | check_sizeof(ptrdiff_t, ptr_width); 49 | check_sizeof(int8_t, 1); 50 | check_sizeof(uint8_t, 1); 51 | check_sizeof(int16_t, 2); 52 | check_sizeof(uint16_t, 2); 53 | check_sizeof(int32_t, 4); 54 | check_sizeof(uint32_t, 4); 55 | check_sizeof(int64_t, 8); 56 | check_sizeof(uint64_t, 8); 57 | 58 | #define check_size_atleast(T,b) \ 59 | if (sizeof(T) < b) { \ 60 | result = -1; \ 61 | fprintf(stderr, #T " %u < %u\n", (unsigned)sizeof(T), b); \ 62 | } 63 | 64 | check_size_atleast(int_least8_t, 1); 65 | check_size_atleast(int_least16_t, 2); 66 | check_size_atleast(int_least32_t, 4); 67 | check_size_atleast(int_least64_t, 8); 68 | check_size_atleast(uint_least8_t, 1); 69 | check_size_atleast(uint_least16_t, 2); 70 | check_size_atleast(uint_least32_t, 4); 71 | check_size_atleast(uint_least64_t, 8); 72 | 73 | check_size_atleast(int_fast8_t, 1); 74 | check_size_atleast(int_fast16_t, 2); 75 | check_size_atleast(int_fast32_t, 4); 76 | check_size_atleast(int_fast64_t, 8); 77 | check_size_atleast(uint_fast8_t, 1); 78 | check_size_atleast(uint_fast16_t, 2); 79 | check_size_atleast(uint_fast32_t, 4); 80 | check_size_atleast(uint_fast64_t, 8); 81 | 82 | check_equal("SCHAR_MAX", "%d", 127, SCHAR_MAX); 83 | check_equal("UCHAR_MAX", "%d", 255, UCHAR_MAX); 84 | if ((int)((char)-1) == -1) { 85 | check_equal("CHAR_MAX", "%d", SCHAR_MAX, CHAR_MAX); 86 | } else { 87 | check_equal("CHAR_MAX", "%d", UCHAR_MAX, CHAR_MAX); 88 | } 89 | 90 | if (INT_MAX == 2147483647) { 91 | check_equal("UINT_MAX", "%u", 0xffffffff, UINT_MAX); 92 | check_sizeof(int, 4); 93 | check_sizeof(unsigned, 4); 94 | } else { 95 | fail("unhandled INT_MAX value %d", INT_MAX); 96 | } 97 | 98 | if (LONG_MAX == 2147483647L) { 99 | check_equal("ULONG_MAX", "%lu", 0xffffffff, ULONG_MAX); 100 | check_sizeof(long, 4); 101 | check_sizeof(unsigned long, 4); 102 | } else if (LONG_MAX == 9223372036854775807L) { 103 | check_equal("ULONG_MAX", "%lu", 0xffffffffffffffff, ULONG_MAX); 104 | check_sizeof(long, 8); 105 | check_sizeof(unsigned long, 8); 106 | } else { 107 | fail("unhandled LONG_MAX value %d", LONG_MAX); 108 | } 109 | 110 | if (LLONG_MAX == 9223372036854775807) { 111 | check_equal("ULLONG_MAX", "%lu", 0xffffffffffffffff, ULLONG_MAX); 112 | check_sizeof(long long, 8); 113 | check_sizeof(unsigned long long, 8); 114 | } else { 115 | fail("unhandled LLONG_MAX value %lld", LONG_MAX); 116 | } 117 | 118 | if (DBL_MANT_DIG == 53) { 119 | check_sizeof(double, 8); 120 | } else { 121 | fail("unhandled DBL_MANT_DIG %u", (unsigned)DBL_MANT_DIG); 122 | } 123 | 124 | check_equal("UINT64_C(0xffff...)", "%llu", 0xffffffffffffffffllu, UINT64_C(0xffffffffffffffff)); 125 | 126 | if (result == 0) { 127 | printf("Success!\n"); 128 | } 129 | return result; 130 | } 131 | -------------------------------------------------------------------------------- /ziglibcbuild.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const build = std.Build; 3 | const CompileStep = build.Step.Compile; 4 | 5 | pub const LinkKind = enum { static, shared }; 6 | pub const LibVariant = enum { 7 | only_std, 8 | only_posix, 9 | only_linux, 10 | only_gnu, 11 | full, 12 | }; 13 | pub const Start = enum { 14 | ziglibc, 15 | glibc, 16 | }; 17 | pub const ZigLibcOptions = struct { 18 | variant: LibVariant, 19 | link: LinkKind, 20 | start: Start, 21 | trace: bool, 22 | target: std.zig.CrossTarget, 23 | optimize: std.builtin.Mode, 24 | }; 25 | 26 | fn relpath(comptime src_path: []const u8) std.Build.LazyPath { 27 | if (comptime std.fs.path.dirname(@src().file)) |dir| 28 | return .{ .path = dir ++ std.fs.path.sep_str ++ src_path }; 29 | return .{ .path = src_path }; 30 | } 31 | 32 | /// Provides a _start symbol that will call C main 33 | pub fn addZigStart( 34 | builder: *build, 35 | target: std.zig.CrossTarget, 36 | optimize: anytype, 37 | ) *CompileStep { 38 | const lib = builder.addStaticLibrary(.{ 39 | .name = "start", 40 | .root_source_file = relpath("src" ++ std.fs.path.sep_str ++ "start.zig"), 41 | .target = target, 42 | .optimize = optimize, 43 | }); 44 | // TODO: not sure if this is reallly needed or not, but it shouldn't hurt 45 | // anything except performance to enable it 46 | lib.force_pic = true; 47 | return lib; 48 | } 49 | 50 | // Returns ziglibc as a CompileStep 51 | // Caller will also need to add the include path to get the C headers 52 | pub fn addLibc(builder: *std.build.Builder, opt: ZigLibcOptions) *CompileStep { 53 | const name = switch (opt.variant) { 54 | .only_std => "c-only-std", 55 | .only_posix => "c-only-posix", 56 | .only_linux => "c-only-linux", 57 | .only_gnu => "c-only-gnu", 58 | //.full => "c", 59 | .full => "cguana", // use cguana to avoid passing in '-lc' to zig which will 60 | // cause it to add the system libc headers 61 | }; 62 | const trace_options = builder.addOptions(); 63 | trace_options.addOption(bool, "enabled", opt.trace); 64 | 65 | const modules_options = builder.addOptions(); 66 | modules_options.addOption(bool, "glibcstart", switch (opt.start) { 67 | .glibc => true, 68 | else => false, 69 | }); 70 | const index = relpath("src" ++ std.fs.path.sep_str ++ "lib.zig"); 71 | const lib = switch (opt.link) { 72 | .static => builder.addStaticLibrary(.{ 73 | .name = name, 74 | .root_source_file = index, 75 | .target = opt.target, 76 | .optimize = opt.optimize, 77 | }), 78 | .shared => builder.addSharedLibrary(.{ 79 | .name = name, 80 | .root_source_file = index, 81 | .target = opt.target, 82 | .optimize = opt.optimize, 83 | .version = switch (opt.variant) { 84 | .full => .{ .major = 6, .minor = 0, .patch = 0 }, 85 | else => null, 86 | }, 87 | }), 88 | }; 89 | // TODO: not sure if this is reallly needed or not, but it shouldn't hurt 90 | // anything except performance to enable it 91 | lib.force_pic = true; 92 | lib.addOptions("modules", modules_options); 93 | lib.addOptions("trace_options", trace_options); 94 | const c_flags = [_][]const u8{ 95 | "-std=c11", 96 | }; 97 | const include_cstd = switch (opt.variant) { 98 | .only_std, .full => true, 99 | else => false, 100 | }; 101 | modules_options.addOption(bool, "cstd", include_cstd); 102 | if (include_cstd) { 103 | lib.addCSourceFile(.{ .file = relpath("src" ++ std.fs.path.sep_str ++ "printf.c"), .flags = &c_flags }); 104 | lib.addCSourceFile(.{ .file = relpath("src" ++ std.fs.path.sep_str ++ "scanf.c"), .flags = &c_flags }); 105 | if (opt.target.getOsTag() == .linux) { 106 | lib.addAssemblyFile(relpath("src/linux/jmp.s")); 107 | } 108 | } 109 | const include_posix = switch (opt.variant) { 110 | .only_posix, .full => true, 111 | else => false, 112 | }; 113 | modules_options.addOption(bool, "posix", include_posix); 114 | if (include_posix) { 115 | lib.addCSourceFile(.{ .file = relpath("src" ++ std.fs.path.sep_str ++ "posix.c"), .flags = &c_flags }); 116 | } 117 | const include_linux = switch (opt.variant) { 118 | .only_linux, .full => true, 119 | else => false, 120 | }; 121 | modules_options.addOption(bool, "linux", include_linux); 122 | if (include_cstd or include_posix) { 123 | lib.addIncludePath(relpath("inc" ++ std.fs.path.sep_str ++ "libc")); 124 | lib.addIncludePath(relpath("inc" ++ std.fs.path.sep_str ++ "posix")); 125 | } 126 | const include_gnu = switch (opt.variant) { 127 | .only_gnu, .full => true, 128 | else => false, 129 | }; 130 | modules_options.addOption(bool, "gnu", include_gnu); 131 | if (include_gnu) { 132 | lib.addIncludePath(relpath("inc" ++ std.fs.path.sep_str ++ "gnu")); 133 | } 134 | return lib; 135 | } 136 | --------------------------------------------------------------------------------