| author | |
| committer | |
| log | b61a6ec8a6ba7222efd3749a9c5ae30db7e4ef6b |
| tree | 252787d924d7753b3e8f5d1e1452c8986c1c9af8 |
| parent | 717e791db2c49c46a913c574946e9f410a6d9168 |
See #3028 files changed, 320 insertions(+), 56 deletions(-)
example/cat/main.zig+12-4| ... | @@ -4,11 +4,12 @@ const mem = std.mem; | ... | @@ -4,11 +4,12 @@ const mem = std.mem; |
| 4 | const os = std.os; | 4 | const os = std.os; |
| 5 | 5 | ||
| 6 | pub fn main() -> %void { | 6 | pub fn main() -> %void { |
| 7 | const exe = os.args.at(0); | 7 | const allocator = &std.debug.global_allocator; |
| 8 | var args_it = os.args(); | ||
| 9 | const exe = %return unwrapArg(??args_it.next(allocator)); | ||
| 8 | var catted_anything = false; | 10 | var catted_anything = false; |
| 9 | var arg_i: usize = 1; | 11 | while (args_it.next(allocator)) |arg_or_err| { |
| 10 | while (arg_i < os.args.count()) : (arg_i += 1) { | 12 | const arg = %return unwrapArg(arg_or_err); |
| 11 | const arg = os.args.at(arg_i); | ||
| 12 | if (mem.eql(u8, arg, "-")) { | 13 | if (mem.eql(u8, arg, "-")) { |
| 13 | catted_anything = true; | 14 | catted_anything = true; |
| 14 | %return cat_stream(&io.stdin); | 15 | %return cat_stream(&io.stdin); |
| ... | @@ -55,3 +56,10 @@ fn cat_stream(is: &io.InStream) -> %void { | ... | @@ -55,3 +56,10 @@ fn cat_stream(is: &io.InStream) -> %void { |
| 55 | }; | 56 | }; |
| 56 | } | 57 | } |
| 57 | } | 58 | } |
| 59 | |||
| 60 | fn unwrapArg(arg: %[]u8) -> %[]u8 { | ||
| 61 | return arg %% |err| { | ||
| 62 | %%io.stderr.printf("Unable to parse command line: {}\n", err); | ||
| 63 | return err; | ||
| 64 | }; | ||
| 65 | } |
std/array_list.zig+20| ... | @@ -14,6 +14,7 @@ pub fn ArrayList(comptime T: type) -> type{ | ... | @@ -14,6 +14,7 @@ pub fn ArrayList(comptime T: type) -> type{ |
| 14 | len: usize, | 14 | len: usize, |
| 15 | allocator: &Allocator, | 15 | allocator: &Allocator, |
| 16 | 16 | ||
| 17 | /// Deinitialize with `deinit` or use `toOwnedSlice`. | ||
| 17 | pub fn init(allocator: &Allocator) -> Self { | 18 | pub fn init(allocator: &Allocator) -> Self { |
| 18 | Self { | 19 | Self { |
| 19 | .items = []T{}, | 20 | .items = []T{}, |
| ... | @@ -34,6 +35,25 @@ pub fn ArrayList(comptime T: type) -> type{ | ... | @@ -34,6 +35,25 @@ pub fn ArrayList(comptime T: type) -> type{ |
| 34 | return l.items[0..l.len]; | 35 | return l.items[0..l.len]; |
| 35 | } | 36 | } |
| 36 | 37 | ||
| 38 | /// ArrayList takes ownership of the passed in slice. The slice must have been | ||
| 39 | /// allocated with `allocator`. | ||
| 40 | /// Deinitialize with `deinit` or use `toOwnedSlice`. | ||
| 41 | pub fn fromOwnedSlice(allocator: &Allocator, slice: []T) -> Self { | ||
| 42 | return Self { | ||
| 43 | .items = slice, | ||
| 44 | .len = slice.len, | ||
| 45 | .allocator = allocator, | ||
| 46 | }; | ||
| 47 | } | ||
| 48 | |||
| 49 | /// The caller owns the returned memory. ArrayList becomes empty. | ||
| 50 | pub fn toOwnedSlice(self: &Self) -> []T { | ||
| 51 | const allocator = self.allocator; | ||
| 52 | const result = allocator.shrink(T, self.items, self.len); | ||
| 53 | *self = init(allocator); | ||
| 54 | return result; | ||
| 55 | } | ||
| 56 | |||
| 37 | pub fn append(l: &Self, item: &const T) -> %void { | 57 | pub fn append(l: &Self, item: &const T) -> %void { |
| 38 | const new_item_ptr = %return l.addOne(); | 58 | const new_item_ptr = %return l.addOne(); |
| 39 | *new_item_ptr = *item; | 59 | *new_item_ptr = *item; |
std/buffer.zig+21| ... | @@ -38,6 +38,27 @@ pub const Buffer = struct { | ... | @@ -38,6 +38,27 @@ pub const Buffer = struct { |
| 38 | return Buffer.init(buffer.list.allocator, buffer.toSliceConst()); | 38 | return Buffer.init(buffer.list.allocator, buffer.toSliceConst()); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | /// Buffer takes ownership of the passed in slice. The slice must have been | ||
| 42 | /// allocated with `allocator`. | ||
| 43 | /// Must deinitialize with deinit. | ||
| 44 | pub fn fromOwnedSlice(allocator: &Allocator, slice: []u8) -> Buffer { | ||
| 45 | var self = Buffer { | ||
| 46 | .list = ArrayList(u8).fromOwnedSlice(allocator, slice), | ||
| 47 | }; | ||
| 48 | self.list.append(0); | ||
| 49 | return self; | ||
| 50 | } | ||
| 51 | |||
| 52 | /// The caller owns the returned memory. The Buffer becomes null and | ||
| 53 | /// is safe to `deinit`. | ||
| 54 | pub fn toOwnedSlice(self: &Buffer) -> []u8 { | ||
| 55 | const allocator = self.list.allocator; | ||
| 56 | const result = allocator.shrink(u8, self.list.items, self.len()); | ||
| 57 | *self = initNull(allocator); | ||
| 58 | return result; | ||
| 59 | } | ||
| 60 | |||
| 61 | |||
| 41 | pub fn deinit(self: &Buffer) { | 62 | pub fn deinit(self: &Buffer) { |
| 42 | self.list.deinit(); | 63 | self.list.deinit(); |
| 43 | } | 64 | } |
std/os/index.zig+230-12| ... | @@ -1,5 +1,7 @@ | ... | @@ -1,5 +1,7 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const builtin = @import("builtin"); |
| 2 | const Os = builtin.Os; | 2 | const Os = builtin.Os; |
| 3 | const is_windows = builtin.os == Os.windows; | ||
| 4 | |||
| 3 | pub const windows = @import("windows/index.zig"); | 5 | pub const windows = @import("windows/index.zig"); |
| 4 | pub const darwin = @import("darwin.zig"); | 6 | pub const darwin = @import("darwin.zig"); |
| 5 | pub const linux = @import("linux.zig"); | 7 | pub const linux = @import("linux.zig"); |
| ... | @@ -37,6 +39,7 @@ const cstr = @import("../cstr.zig"); | ... | @@ -37,6 +39,7 @@ const cstr = @import("../cstr.zig"); |
| 37 | const io = @import("../io.zig"); | 39 | const io = @import("../io.zig"); |
| 38 | const base64 = @import("../base64.zig"); | 40 | const base64 = @import("../base64.zig"); |
| 39 | const ArrayList = @import("../array_list.zig").ArrayList; | 41 | const ArrayList = @import("../array_list.zig").ArrayList; |
| 42 | const Buffer = @import("../buffer.zig").Buffer; | ||
| 40 | 43 | ||
| 41 | error Unexpected; | 44 | error Unexpected; |
| 42 | error SystemResources; | 45 | error SystemResources; |
| ... | @@ -513,18 +516,6 @@ pub fn getEnv(key: []const u8) -> ?[]const u8 { | ... | @@ -513,18 +516,6 @@ pub fn getEnv(key: []const u8) -> ?[]const u8 { |
| 513 | return null; | 516 | return null; |
| 514 | } | 517 | } |
| 515 | 518 | ||
| 516 | pub const args = struct { | ||
| 517 | pub var raw: []&u8 = undefined; | ||
| 518 | |||
| 519 | pub fn count() -> usize { | ||
| 520 | return raw.len; | ||
| 521 | } | ||
| 522 | pub fn at(i: usize) -> []const u8 { | ||
| 523 | const s = raw[i]; | ||
| 524 | return cstr.toSlice(s); | ||
| 525 | } | ||
| 526 | }; | ||
| 527 | |||
| 528 | /// Caller must free the returned memory. | 519 | /// Caller must free the returned memory. |
| 529 | pub fn getCwd(allocator: &Allocator) -> %[]u8 { | 520 | pub fn getCwd(allocator: &Allocator) -> %[]u8 { |
| 530 | switch (builtin.os) { | 521 | switch (builtin.os) { |
| ... | @@ -1144,6 +1135,233 @@ pub fn posix_setregid(rgid: u32, egid: u32) -> %void { | ... | @@ -1144,6 +1135,233 @@ pub fn posix_setregid(rgid: u32, egid: u32) -> %void { |
| 1144 | }; | 1135 | }; |
| 1145 | } | 1136 | } |
| 1146 | 1137 | ||
| 1138 | pub const ArgIteratorPosix = struct { | ||
| 1139 | index: usize, | ||
| 1140 | count: usize, | ||
| 1141 | |||
| 1142 | pub fn init() -> ArgIteratorPosix { | ||
| 1143 | return ArgIteratorPosix { | ||
| 1144 | .index = 0, | ||
| 1145 | .count = raw.len, | ||
| 1146 | }; | ||
| 1147 | } | ||
| 1148 | |||
| 1149 | pub fn next(self: &ArgIteratorPosix) -> ?[]const u8 { | ||
| 1150 | if (self.index == self.count) | ||
| 1151 | return null; | ||
| 1152 | |||
| 1153 | const s = raw[self.index]; | ||
| 1154 | self.index += 1; | ||
| 1155 | return cstr.toSlice(s); | ||
| 1156 | } | ||
| 1157 | |||
| 1158 | pub fn skip(self: &ArgIteratorPosix) -> bool { | ||
| 1159 | if (self.index == self.count) | ||
| 1160 | return false; | ||
| 1161 | |||
| 1162 | self.index += 1; | ||
| 1163 | return true; | ||
| 1164 | } | ||
| 1165 | |||
| 1166 | /// This is marked as public but actually it's only meant to be used | ||
| 1167 | /// internally by zig's startup code. | ||
| 1168 | pub var raw: []&u8 = undefined; | ||
| 1169 | }; | ||
| 1170 | |||
| 1171 | pub const ArgIteratorWindows = struct { | ||
| 1172 | index: usize, | ||
| 1173 | cmd_line: &const u8, | ||
| 1174 | backslash_count: usize, | ||
| 1175 | in_quote: bool, | ||
| 1176 | quote_count: usize, | ||
| 1177 | seen_quote_count: usize, | ||
| 1178 | |||
| 1179 | pub fn init() -> ArgIteratorWindows { | ||
| 1180 | return initWithCmdLine(windows.GetCommandLineA()); | ||
| 1181 | } | ||
| 1182 | |||
| 1183 | pub fn initWithCmdLine(cmd_line: &const u8) -> ArgIteratorWindows { | ||
| 1184 | return ArgIteratorWindows { | ||
| 1185 | .index = 0, | ||
| 1186 | .cmd_line = cmd_line, | ||
| 1187 | .backslash_count = 0, | ||
| 1188 | .in_quote = false, | ||
| 1189 | .quote_count = countQuotes(cmd_line), | ||
| 1190 | .seen_quote_count = 0, | ||
| 1191 | }; | ||
| 1192 | } | ||
| 1193 | |||
| 1194 | /// You must free the returned memory when done. | ||
| 1195 | pub fn next(self: &ArgIteratorWindows, allocator: &Allocator) -> ?%[]u8 { | ||
| 1196 | // march forward over whitespace | ||
| 1197 | while (true) : (self.index += 1) { | ||
| 1198 | const byte = self.cmd_line[self.index]; | ||
| 1199 | switch (byte) { | ||
| 1200 | 0 => return null, | ||
| 1201 | ' ', '\t' => continue, | ||
| 1202 | else => break, | ||
| 1203 | } | ||
| 1204 | } | ||
| 1205 | |||
| 1206 | return self.internalNext(allocator); | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | pub fn skip(self: &ArgIteratorWindows) -> bool { | ||
| 1210 | // march forward over whitespace | ||
| 1211 | while (true) : (self.index += 1) { | ||
| 1212 | const byte = self.cmd_line[self.index]; | ||
| 1213 | switch (byte) { | ||
| 1214 | 0 => return false, | ||
| 1215 | ' ', '\t' => continue, | ||
| 1216 | else => break, | ||
| 1217 | } | ||
| 1218 | } | ||
| 1219 | |||
| 1220 | while (true) : (self.index += 1) { | ||
| 1221 | const byte = self.cmd_line[self.index]; | ||
| 1222 | switch (byte) { | ||
| 1223 | 0 => return true, | ||
| 1224 | '"' => { | ||
| 1225 | const quote_is_real = self.backslash_count % 2 == 0; | ||
| 1226 | if (quote_is_real) { | ||
| 1227 | self.seen_quote_count += 1; | ||
| 1228 | } | ||
| 1229 | }, | ||
| 1230 | '\\' => { | ||
| 1231 | self.backslash_count += 1; | ||
| 1232 | }, | ||
| 1233 | ' ', '\t' => { | ||
| 1234 | if (self.seen_quote_count % 2 == 0 or self.seen_quote_count == self.quote_count) { | ||
| 1235 | return true; | ||
| 1236 | } | ||
| 1237 | }, | ||
| 1238 | else => continue, | ||
| 1239 | } | ||
| 1240 | } | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | fn internalNext(self: &ArgIteratorWindows, allocator: &Allocator) -> %[]u8 { | ||
| 1244 | var buf = %return Buffer.initSize(allocator, 0); | ||
| 1245 | defer buf.deinit(); | ||
| 1246 | |||
| 1247 | while (true) : (self.index += 1) { | ||
| 1248 | const byte = self.cmd_line[self.index]; | ||
| 1249 | switch (byte) { | ||
| 1250 | 0 => return buf.toOwnedSlice(), | ||
| 1251 | '"' => { | ||
| 1252 | const quote_is_real = self.backslash_count % 2 == 0; | ||
| 1253 | %return self.emitBackslashes(&buf, self.backslash_count / 2); | ||
| 1254 | |||
| 1255 | if (quote_is_real) { | ||
| 1256 | self.seen_quote_count += 1; | ||
| 1257 | if (self.seen_quote_count == self.quote_count and self.seen_quote_count % 2 == 1) { | ||
| 1258 | %return buf.appendByte('"'); | ||
| 1259 | } | ||
| 1260 | } else { | ||
| 1261 | %return buf.appendByte('"'); | ||
| 1262 | } | ||
| 1263 | }, | ||
| 1264 | '\\' => { | ||
| 1265 | self.backslash_count += 1; | ||
| 1266 | }, | ||
| 1267 | ' ', '\t' => { | ||
| 1268 | %return self.emitBackslashes(&buf, self.backslash_count); | ||
| 1269 | if (self.seen_quote_count % 2 == 1 and self.seen_quote_count != self.quote_count) { | ||
| 1270 | %return buf.appendByte(byte); | ||
| 1271 | } else { | ||
| 1272 | return buf.toOwnedSlice(); | ||
| 1273 | } | ||
| 1274 | }, | ||
| 1275 | else => { | ||
| 1276 | %return self.emitBackslashes(&buf, self.backslash_count); | ||
| 1277 | %return buf.appendByte(byte); | ||
| 1278 | }, | ||
| 1279 | } | ||
| 1280 | } | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | fn emitBackslashes(self: &ArgIteratorWindows, buf: &Buffer, emit_count: usize) -> %void { | ||
| 1284 | self.backslash_count = 0; | ||
| 1285 | var i: usize = 0; | ||
| 1286 | while (i < emit_count) : (i += 1) { | ||
| 1287 | %return buf.appendByte('\\'); | ||
| 1288 | } | ||
| 1289 | } | ||
| 1290 | |||
| 1291 | fn countQuotes(cmd_line: &const u8) -> usize { | ||
| 1292 | var result: usize = 0; | ||
| 1293 | var backslash_count: usize = 0; | ||
| 1294 | var index: usize = 0; | ||
| 1295 | while (true) : (index += 1) { | ||
| 1296 | const byte = cmd_line[index]; | ||
| 1297 | switch (byte) { | ||
| 1298 | 0 => return result, | ||
| 1299 | '\\' => backslash_count += 1, | ||
| 1300 | '"' => { | ||
| 1301 | result += 1 - (backslash_count % 2); | ||
| 1302 | backslash_count = 0; | ||
| 1303 | }, | ||
| 1304 | else => { | ||
| 1305 | backslash_count = 0; | ||
| 1306 | }, | ||
| 1307 | } | ||
| 1308 | } | ||
| 1309 | } | ||
| 1310 | |||
| 1311 | }; | ||
| 1312 | |||
| 1313 | pub const ArgIterator = struct { | ||
| 1314 | inner: if (builtin.os == Os.windows) ArgIteratorWindows else ArgIteratorPosix, | ||
| 1315 | |||
| 1316 | pub fn init() -> ArgIterator { | ||
| 1317 | return ArgIterator { | ||
| 1318 | .inner = if (builtin.os == Os.windows) ArgIteratorWindows.init() else ArgIteratorPosix.init(), | ||
| 1319 | }; | ||
| 1320 | } | ||
| 1321 | |||
| 1322 | /// You must free the returned memory when done. | ||
| 1323 | pub fn next(self: &ArgIterator, allocator: &Allocator) -> ?%[]u8 { | ||
| 1324 | if (builtin.os == Os.windows) { | ||
| 1325 | return self.inner.next(allocator); | ||
| 1326 | } else { | ||
| 1327 | return mem.dupe(allocator, u8, self.inner.next() ?? return null); | ||
| 1328 | } | ||
| 1329 | } | ||
| 1330 | |||
| 1331 | /// If you only are targeting posix you can call this and not need an allocator. | ||
| 1332 | pub fn nextPosix(self: &ArgIterator) -> ?[]const u8 { | ||
| 1333 | return self.inner.next(); | ||
| 1334 | } | ||
| 1335 | |||
| 1336 | /// Parse past 1 argument without capturing it. | ||
| 1337 | /// Returns `true` if skipped an arg, `false` if we are at the end. | ||
| 1338 | pub fn skip(self: &ArgIterator) -> bool { | ||
| 1339 | return self.inner.skip(); | ||
| 1340 | } | ||
| 1341 | }; | ||
| 1342 | |||
| 1343 | pub fn args() -> ArgIterator { | ||
| 1344 | return ArgIterator.init(); | ||
| 1345 | } | ||
| 1346 | |||
| 1347 | test "windows arg parsing" { | ||
| 1348 | testWindowsCmdLine(c"a b\tc d", [][]const u8{"a", "b", "c", "d"}); | ||
| 1349 | testWindowsCmdLine(c"\"abc\" d e", [][]const u8{"abc", "d", "e"}); | ||
| 1350 | testWindowsCmdLine(c"a\\\\\\b d\"e f\"g h", [][]const u8{"a\\\\\\b", "de fg", "h"}); | ||
| 1351 | testWindowsCmdLine(c"a\\\\\\\"b c d", [][]const u8{"a\\\"b", "c", "d"}); | ||
| 1352 | testWindowsCmdLine(c"a\\\\\\\\\"b c\" d e", [][]const u8{"a\\\\b c", "d", "e"}); | ||
| 1353 | testWindowsCmdLine(c"a b\tc \"d f", [][]const u8{"a", "b", "c", "\"d", "f"}); | ||
| 1354 | } | ||
| 1355 | |||
| 1356 | fn testWindowsCmdLine(input_cmd_line: &const u8, expected_args: []const []const u8) { | ||
| 1357 | var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line); | ||
| 1358 | for (expected_args) |expected_arg| { | ||
| 1359 | const arg = %%??it.next(&debug.global_allocator); | ||
| 1360 | assert(mem.eql(u8, arg, expected_arg)); | ||
| 1361 | } | ||
| 1362 | assert(it.next(&debug.global_allocator) == null); | ||
| 1363 | } | ||
| 1364 | |||
| 1147 | test "std.os" { | 1365 | test "std.os" { |
| 1148 | _ = @import("child_process.zig"); | 1366 | _ = @import("child_process.zig"); |
| 1149 | _ = @import("darwin_errno.zig"); | 1367 | _ = @import("darwin_errno.zig"); |
std/os/windows/index.zig+1-1| ... | @@ -17,7 +17,7 @@ pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: LPCSTR) -> bool; | ... | @@ -17,7 +17,7 @@ pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: LPCSTR) -> bool; |
| 17 | 17 | ||
| 18 | pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) -> noreturn; | 18 | pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) -> noreturn; |
| 19 | 19 | ||
| 20 | pub extern "kernel32" stdcallcc fn GetCommandLine() -> LPTSTR; | 20 | pub extern "kernel32" stdcallcc fn GetCommandLineA() -> LPSTR; |
| 21 | 21 | ||
| 22 | pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: &DWORD) -> bool; | 22 | pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: &DWORD) -> bool; |
| 23 | 23 |
std/special/bootstrap.zig+1-1| ... | @@ -52,7 +52,7 @@ fn posixCallMainAndExit() -> noreturn { | ... | @@ -52,7 +52,7 @@ fn posixCallMainAndExit() -> noreturn { |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void { | 54 | fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void { |
| 55 | std.os.args.raw = argv[0..argc]; | 55 | std.os.ArgIteratorPosix.raw = argv[0..argc]; |
| 56 | 56 | ||
| 57 | var env_count: usize = 0; | 57 | var env_count: usize = 0; |
| 58 | while (envp[env_count] != null) : (env_count += 1) {} | 58 | while (envp[env_count] != null) : (env_count += 1) {} |
std/special/build_runner.zig+33-37| ... | @@ -10,37 +10,7 @@ const ArrayList = std.ArrayList; | ... | @@ -10,37 +10,7 @@ const ArrayList = std.ArrayList; |
| 10 | error InvalidArgs; | 10 | error InvalidArgs; |
| 11 | 11 | ||
| 12 | pub fn main() -> %void { | 12 | pub fn main() -> %void { |
| 13 | var arg_i: usize = 1; | 13 | var arg_it = os.args(); |
| 14 | |||
| 15 | const zig_exe = { | ||
| 16 | if (arg_i >= os.args.count()) { | ||
| 17 | %%io.stderr.printf("Expected first argument to be path to zig compiler\n"); | ||
| 18 | return error.InvalidArgs; | ||
| 19 | } | ||
| 20 | const result = os.args.at(arg_i); | ||
| 21 | arg_i += 1; | ||
| 22 | result | ||
| 23 | }; | ||
| 24 | |||
| 25 | const build_root = { | ||
| 26 | if (arg_i >= os.args.count()) { | ||
| 27 | %%io.stderr.printf("Expected second argument to be build root directory path\n"); | ||
| 28 | return error.InvalidArgs; | ||
| 29 | } | ||
| 30 | const result = os.args.at(arg_i); | ||
| 31 | arg_i += 1; | ||
| 32 | result | ||
| 33 | }; | ||
| 34 | |||
| 35 | const cache_root = { | ||
| 36 | if (arg_i >= os.args.count()) { | ||
| 37 | %%io.stderr.printf("Expected third argument to be cache root directory path\n"); | ||
| 38 | return error.InvalidArgs; | ||
| 39 | } | ||
| 40 | const result = os.args.at(arg_i); | ||
| 41 | arg_i += 1; | ||
| 42 | result | ||
| 43 | }; | ||
| 44 | 14 | ||
| 45 | // TODO use a more general purpose allocator here | 15 | // TODO use a more general purpose allocator here |
| 46 | var inc_allocator = %%mem.IncrementingAllocator.init(20 * 1024 * 1024); | 16 | var inc_allocator = %%mem.IncrementingAllocator.init(20 * 1024 * 1024); |
| ... | @@ -48,6 +18,23 @@ pub fn main() -> %void { | ... | @@ -48,6 +18,23 @@ pub fn main() -> %void { |
| 48 | 18 | ||
| 49 | const allocator = &inc_allocator.allocator; | 19 | const allocator = &inc_allocator.allocator; |
| 50 | 20 | ||
| 21 | |||
| 22 | // skip my own exe name | ||
| 23 | _ = arg_it.skip(); | ||
| 24 | |||
| 25 | const zig_exe = %return unwrapArg(arg_it.next(allocator) ?? { | ||
| 26 | %%io.stderr.printf("Expected first argument to be path to zig compiler\n"); | ||
| 27 | return error.InvalidArgs; | ||
| 28 | }); | ||
| 29 | const build_root = %return unwrapArg(arg_it.next(allocator) ?? { | ||
| 30 | %%io.stderr.printf("Expected second argument to be build root directory path\n"); | ||
| 31 | return error.InvalidArgs; | ||
| 32 | }); | ||
| 33 | const cache_root = %return unwrapArg(arg_it.next(allocator) ?? { | ||
| 34 | %%io.stderr.printf("Expected third argument to be cache root directory path\n"); | ||
| 35 | return error.InvalidArgs; | ||
| 36 | }); | ||
| 37 | |||
| 51 | var builder = Builder.init(allocator, zig_exe, build_root, cache_root); | 38 | var builder = Builder.init(allocator, zig_exe, build_root, cache_root); |
| 52 | defer builder.deinit(); | 39 | defer builder.deinit(); |
| 53 | 40 | ||
| ... | @@ -55,8 +42,8 @@ pub fn main() -> %void { | ... | @@ -55,8 +42,8 @@ pub fn main() -> %void { |
| 55 | 42 | ||
| 56 | var prefix: ?[]const u8 = null; | 43 | var prefix: ?[]const u8 = null; |
| 57 | 44 | ||
| 58 | while (arg_i < os.args.count()) : (arg_i += 1) { | 45 | while (arg_it.next(allocator)) |err_or_arg| { |
| 59 | const arg = os.args.at(arg_i); | 46 | const arg = %return unwrapArg(err_or_arg); |
| 60 | if (mem.startsWith(u8, arg, "-D")) { | 47 | if (mem.startsWith(u8, arg, "-D")) { |
| 61 | const option_contents = arg[2..]; | 48 | const option_contents = arg[2..]; |
| 62 | if (option_contents.len == 0) { | 49 | if (option_contents.len == 0) { |
| ... | @@ -76,10 +63,12 @@ pub fn main() -> %void { | ... | @@ -76,10 +63,12 @@ pub fn main() -> %void { |
| 76 | if (mem.eql(u8, arg, "--verbose")) { | 63 | if (mem.eql(u8, arg, "--verbose")) { |
| 77 | builder.verbose = true; | 64 | builder.verbose = true; |
| 78 | } else if (mem.eql(u8, arg, "--help")) { | 65 | } else if (mem.eql(u8, arg, "--help")) { |
| 79 | return usage(&builder, false, &io.stdout); | 66 | return usage(&builder, false, &io.stdout); |
| 80 | } else if (mem.eql(u8, arg, "--prefix") and arg_i + 1 < os.args.count()) { | 67 | } else if (mem.eql(u8, arg, "--prefix")) { |
| 81 | arg_i += 1; | 68 | prefix = %return unwrapArg(arg_it.next(allocator) ?? { |
| 82 | prefix = os.args.at(arg_i); | 69 | %%io.stderr.printf("Expected argument after --prefix\n\n"); |
| 70 | return usage(&builder, false, &io.stderr); | ||
| 71 | }); | ||
| 83 | } else { | 72 | } else { |
| 84 | %%io.stderr.printf("Unrecognized argument: {}\n\n", arg); | 73 | %%io.stderr.printf("Unrecognized argument: {}\n\n", arg); |
| 85 | return usage(&builder, false, &io.stderr); | 74 | return usage(&builder, false, &io.stderr); |
| ... | @@ -151,3 +140,10 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) | ... | @@ -151,3 +140,10 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) |
| 151 | if (out_stream == &io.stderr) | 140 | if (out_stream == &io.stderr) |
| 152 | return error.InvalidArgs; | 141 | return error.InvalidArgs; |
| 153 | } | 142 | } |
| 143 | |||
| 144 | fn unwrapArg(arg: %[]u8) -> %[]u8 { | ||
| 145 | return arg %% |err| { | ||
| 146 | %%io.stderr.printf("Unable to parse command line: {}\n", err); | ||
| 147 | return err; | ||
| 148 | }; | ||
| 149 | } |
test/compare_output.zig+2-1| ... | @@ -346,7 +346,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -346,7 +346,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 346 | \\ %%io.stdout.printf("before\n"); | 346 | \\ %%io.stdout.printf("before\n"); |
| 347 | \\ defer %%io.stdout.printf("defer1\n"); | 347 | \\ defer %%io.stdout.printf("defer1\n"); |
| 348 | \\ defer %%io.stdout.printf("defer2\n"); | 348 | \\ defer %%io.stdout.printf("defer2\n"); |
| 349 | \\ if (os.args.count() == 1) return; | 349 | \\ var args_it = @import("std").os.args(); |
| 350 | \\ if (args_it.skip() and !args_it.skip()) return; | ||
| 350 | \\ defer %%io.stdout.printf("defer3\n"); | 351 | \\ defer %%io.stdout.printf("defer3\n"); |
| 351 | \\ %%io.stdout.printf("after\n"); | 352 | \\ %%io.stdout.printf("after\n"); |
| 352 | \\} | 353 | \\} |