authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-09-26 01:45:07-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-09-26 01:45:07-07:00
log3b365a1f9b277dd2cf7f7dac51e71647e164ff3c
tree4be6d39eeb3327d8023ef5f2153ac0dcf92a3154
parentad80a8b5529ab70d49feaffc82fcd9a990a05332
parent14e227d8a6dd692ba0707aa070b8bac22a9a822e
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #25351 from ziglang/chomp

std.mem: introduce cut functions; rename "index of" to "find"

2 files changed, 327 insertions(+), 203 deletions(-)

lib/std/mem.zig+220-71
...@@ -806,9 +806,12 @@ fn eqlBytes(a: []const u8, b: []const u8) bool {...@@ -806,9 +806,12 @@ fn eqlBytes(a: []const u8, b: []const u8) bool {
806 return !Scan.isNotEqual(last_a_chunk, last_b_chunk);806 return !Scan.isNotEqual(last_a_chunk, last_b_chunk);
807}807}
808808
809/// Deprecated in favor of `findDiff`.
810pub const indexOfDiff = findDiff;
811
809/// Compares two slices and returns the index of the first inequality.812/// Compares two slices and returns the index of the first inequality.
810/// Returns null if the slices are equal.813/// Returns null if the slices are equal.
811pub fn indexOfDiff(comptime T: type, a: []const T, b: []const T) ?usize {814pub fn findDiff(comptime T: type, a: []const T, b: []const T) ?usize {
812 const shortest = @min(a.len, b.len);815 const shortest = @min(a.len, b.len);
813 if (a.ptr == b.ptr)816 if (a.ptr == b.ptr)
814 return if (a.len == b.len) null else shortest;817 return if (a.len == b.len) null else shortest;
...@@ -817,12 +820,12 @@ pub fn indexOfDiff(comptime T: type, a: []const T, b: []const T) ?usize {...@@ -817,12 +820,12 @@ pub fn indexOfDiff(comptime T: type, a: []const T, b: []const T) ?usize {
817 return if (a.len == b.len) null else shortest;820 return if (a.len == b.len) null else shortest;
818}821}
819822
820test indexOfDiff {823test findDiff {
821 try testing.expectEqual(indexOfDiff(u8, "one", "one"), null);824 try testing.expectEqual(findDiff(u8, "one", "one"), null);
822 try testing.expectEqual(indexOfDiff(u8, "one two", "one"), 3);825 try testing.expectEqual(findDiff(u8, "one two", "one"), 3);
823 try testing.expectEqual(indexOfDiff(u8, "one", "one two"), 3);826 try testing.expectEqual(findDiff(u8, "one", "one two"), 3);
824 try testing.expectEqual(indexOfDiff(u8, "one twx", "one two"), 6);827 try testing.expectEqual(findDiff(u8, "one twx", "one two"), 6);
825 try testing.expectEqual(indexOfDiff(u8, "xne", "one"), 0);828 try testing.expectEqual(findDiff(u8, "xne", "one"), 0);
826}829}
827830
828/// Takes a sentinel-terminated pointer and returns a slice preserving pointer attributes.831/// Takes a sentinel-terminated pointer and returns a slice preserving pointer attributes.
...@@ -1014,7 +1017,7 @@ fn lenSliceTo(ptr: anytype, comptime end: std.meta.Elem(@TypeOf(ptr))) usize {...@@ -1014,7 +1017,7 @@ fn lenSliceTo(ptr: anytype, comptime end: std.meta.Elem(@TypeOf(ptr))) usize {
1014 return indexOfSentinel(array_info.child, end, ptr);1017 return indexOfSentinel(array_info.child, end, ptr);
1015 }1018 }
1016 }1019 }
1017 return indexOfScalar(array_info.child, ptr, end) orelse array_info.len;1020 return findScalar(array_info.child, ptr, end) orelse array_info.len;
1018 },1021 },
1019 else => {},1022 else => {},
1020 },1023 },
...@@ -1039,7 +1042,7 @@ fn lenSliceTo(ptr: anytype, comptime end: std.meta.Elem(@TypeOf(ptr))) usize {...@@ -1039,7 +1042,7 @@ fn lenSliceTo(ptr: anytype, comptime end: std.meta.Elem(@TypeOf(ptr))) usize {
1039 return indexOfSentinel(ptr_info.child, s, ptr);1042 return indexOfSentinel(ptr_info.child, s, ptr);
1040 }1043 }
1041 }1044 }
1042 return indexOfScalar(ptr_info.child, ptr, end) orelse ptr.len;1045 return findScalar(ptr_info.child, ptr, end) orelse ptr.len;
1043 },1046 },
1044 },1047 },
1045 else => {},1048 else => {},
...@@ -1109,9 +1112,12 @@ test len {...@@ -1109,9 +1112,12 @@ test len {
1109 try testing.expect(len(c_ptr) == 2);1112 try testing.expect(len(c_ptr) == 2);
1110}1113}
11111114
1115/// Deprecated in favor of `findSentinel`.
1116pub const indexOfSentinel = findSentinel;
1117
1112/// Returns the index of the sentinel value in a sentinel-terminated pointer.1118/// Returns the index of the sentinel value in a sentinel-terminated pointer.
1113/// Linear search through memory until the sentinel is found.1119/// Linear search through memory until the sentinel is found.
1114pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]const T) usize {1120pub fn findSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]const T) usize {
1115 var i: usize = 0;1121 var i: usize = 0;
11161122
1117 if (use_vectors_for_comparison and1123 if (use_vectors_for_comparison and
...@@ -1223,7 +1229,7 @@ pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool {...@@ -1223,7 +1229,7 @@ pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool {
1223/// Remove a set of values from the beginning of a slice.1229/// Remove a set of values from the beginning of a slice.
1224pub fn trimStart(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {1230pub fn trimStart(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
1225 var begin: usize = 0;1231 var begin: usize = 0;
1226 while (begin < slice.len and indexOfScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {}1232 while (begin < slice.len and findScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {}
1227 return slice[begin..];1233 return slice[begin..];
1228}1234}
12291235
...@@ -1237,7 +1243,7 @@ pub const trimLeft = trimStart;...@@ -1237,7 +1243,7 @@ pub const trimLeft = trimStart;
1237/// Remove a set of values from the end of a slice.1243/// Remove a set of values from the end of a slice.
1238pub fn trimEnd(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {1244pub fn trimEnd(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
1239 var end: usize = slice.len;1245 var end: usize = slice.len;
1240 while (end > 0 and indexOfScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {}1246 while (end > 0 and findScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {}
1241 return slice[0..end];1247 return slice[0..end];
1242}1248}
12431249
...@@ -1252,8 +1258,8 @@ pub const trimRight = trimEnd;...@@ -1252,8 +1258,8 @@ pub const trimRight = trimEnd;
1252pub fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {1258pub fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
1253 var begin: usize = 0;1259 var begin: usize = 0;
1254 var end: usize = slice.len;1260 var end: usize = slice.len;
1255 while (begin < end and indexOfScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {}1261 while (begin < end and findScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {}
1256 while (end > begin and indexOfScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {}1262 while (end > begin and findScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {}
1257 return slice[begin..end];1263 return slice[begin..end];
1258}1264}
12591265
...@@ -1262,13 +1268,19 @@ test trim {...@@ -1262,13 +1268,19 @@ test trim {
1262 try testing.expectEqualSlices(u8, "foo", trim(u8, "foo", " \n"));1268 try testing.expectEqualSlices(u8, "foo", trim(u8, "foo", " \n"));
1263}1269}
12641270
1271/// Deprecated in favor of `findScalar`.
1272pub const indexOfScalar = findScalar;
1273
1265/// Linear search for the index of a scalar value inside a slice.1274/// Linear search for the index of a scalar value inside a slice.
1266pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {1275pub fn findScalar(comptime T: type, slice: []const T, value: T) ?usize {
1267 return indexOfScalarPos(T, slice, 0, value);1276 return indexOfScalarPos(T, slice, 0, value);
1268}1277}
12691278
1279/// Deprecated in favor of `findScalarLast`.
1280pub const lastIndexOfScalar = findScalarLast;
1281
1270/// Linear search for the last index of a scalar value inside a slice.1282/// Linear search for the last index of a scalar value inside a slice.
1271pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {1283pub fn findScalarLast(comptime T: type, slice: []const T, value: T) ?usize {
1272 var i: usize = slice.len;1284 var i: usize = slice.len;
1273 while (i != 0) {1285 while (i != 0) {
1274 i -= 1;1286 i -= 1;
...@@ -1277,9 +1289,12 @@ pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {...@@ -1277,9 +1289,12 @@ pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
1277 return null;1289 return null;
1278}1290}
12791291
1292/// Deprecated in favor of `findScalarPos`.
1293pub const indexOfScalarPos = findScalarPos;
1294
1280/// Linear search for the index of a scalar value inside a slice, starting from a given position.1295/// Linear search for the index of a scalar value inside a slice, starting from a given position.
1281/// Returns null if the value is not found.1296/// Returns null if the value is not found.
1282pub fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {1297pub fn findScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {
1283 if (start_index >= slice.len) return null;1298 if (start_index >= slice.len) return null;
12841299
1285 var i: usize = start_index;1300 var i: usize = start_index;
...@@ -1355,15 +1370,21 @@ test indexOfScalarPos {...@@ -1355,15 +1370,21 @@ test indexOfScalarPos {
1355 }1370 }
1356}1371}
13571372
1373/// Deprecated in favor of `findAny`.
1374pub const indexOfAny = findAny;
1375
1358/// Linear search for the index of any value in the provided list inside a slice.1376/// Linear search for the index of any value in the provided list inside a slice.
1359/// Returns null if no values are found.1377/// Returns null if no values are found.
1360pub fn indexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize {1378pub fn findAny(comptime T: type, slice: []const T, values: []const T) ?usize {
1361 return indexOfAnyPos(T, slice, 0, values);1379 return indexOfAnyPos(T, slice, 0, values);
1362}1380}
13631381
1382/// Deprecated in favor of `findLastAny`.
1383pub const lastIndexOfAny = findLastAny;
1384
1364/// Linear search for the last index of any value in the provided list inside a slice.1385/// Linear search for the last index of any value in the provided list inside a slice.
1365/// Returns null if no values are found.1386/// Returns null if no values are found.
1366pub fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize {1387pub fn findLastAny(comptime T: type, slice: []const T, values: []const T) ?usize {
1367 var i: usize = slice.len;1388 var i: usize = slice.len;
1368 while (i != 0) {1389 while (i != 0) {
1369 i -= 1;1390 i -= 1;
...@@ -1374,9 +1395,12 @@ pub fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?us...@@ -1374,9 +1395,12 @@ pub fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?us
1374 return null;1395 return null;
1375}1396}
13761397
1398/// Deprecated in favor of `findAnyPos`.
1399pub const indexOfAnyPos = findAnyPos;
1400
1377/// Linear search for the index of any value in the provided list inside a slice, starting from a given position.1401/// Linear search for the index of any value in the provided list inside a slice, starting from a given position.
1378/// Returns null if no values are found.1402/// Returns null if no values are found.
1379pub fn indexOfAnyPos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize {1403pub fn findAnyPos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize {
1380 if (start_index >= slice.len) return null;1404 if (start_index >= slice.len) return null;
1381 for (slice[start_index..], start_index..) |c, i| {1405 for (slice[start_index..], start_index..) |c, i| {
1382 for (values) |value| {1406 for (values) |value| {
...@@ -1386,17 +1410,34 @@ pub fn indexOfAnyPos(comptime T: type, slice: []const T, start_index: usize, val...@@ -1386,17 +1410,34 @@ pub fn indexOfAnyPos(comptime T: type, slice: []const T, start_index: usize, val
1386 return null;1410 return null;
1387}1411}
13881412
1413/// Deprecated in favor of `findNone`.
1414pub const indexOfNone = findNone;
1415
1389/// Find the first item in `slice` which is not contained in `values`.1416/// Find the first item in `slice` which is not contained in `values`.
1390///1417///
1391/// Comparable to `strspn` in the C standard library.1418/// Comparable to `strspn` in the C standard library.
1392pub fn indexOfNone(comptime T: type, slice: []const T, values: []const T) ?usize {1419pub fn findNone(comptime T: type, slice: []const T, values: []const T) ?usize {
1393 return indexOfNonePos(T, slice, 0, values);1420 return indexOfNonePos(T, slice, 0, values);
1394}1421}
13951422
1423test findNone {
1424 try testing.expect(findNone(u8, "abc123", "123").? == 0);
1425 try testing.expect(findLastNone(u8, "abc123", "123").? == 2);
1426 try testing.expect(findNone(u8, "123abc", "123").? == 3);
1427 try testing.expect(findLastNone(u8, "123abc", "123").? == 5);
1428 try testing.expect(findNone(u8, "123123", "123") == null);
1429 try testing.expect(findNone(u8, "333333", "123") == null);
1430
1431 try testing.expect(indexOfNonePos(u8, "abc123", 3, "321") == null);
1432}
1433
1434/// Deprecated in favor of `findLastNone`.
1435pub const lastIndexOfNone = findLastNone;
1436
1396/// Find the last item in `slice` which is not contained in `values`.1437/// Find the last item in `slice` which is not contained in `values`.
1397///1438///
1398/// Like `strspn` in the C standard library, but searches from the end.1439/// Like `strspn` in the C standard library, but searches from the end.
1399pub fn lastIndexOfNone(comptime T: type, slice: []const T, values: []const T) ?usize {1440pub fn findLastNone(comptime T: type, slice: []const T, values: []const T) ?usize {
1400 var i: usize = slice.len;1441 var i: usize = slice.len;
1401 outer: while (i != 0) {1442 outer: while (i != 0) {
1402 i -= 1;1443 i -= 1;
...@@ -1408,11 +1449,13 @@ pub fn lastIndexOfNone(comptime T: type, slice: []const T, values: []const T) ?u...@@ -1408,11 +1449,13 @@ pub fn lastIndexOfNone(comptime T: type, slice: []const T, values: []const T) ?u
1408 return null;1449 return null;
1409}1450}
14101451
1452pub const indexOfNonePos = findNonePos;
1453
1411/// Find the first item in `slice[start_index..]` which is not contained in `values`.1454/// Find the first item in `slice[start_index..]` which is not contained in `values`.
1412/// The returned index will be relative to the start of `slice`, and never less than `start_index`.1455/// The returned index will be relative to the start of `slice`, and never less than `start_index`.
1413///1456///
1414/// Comparable to `strspn` in the C standard library.1457/// Comparable to `strspn` in the C standard library.
1415pub fn indexOfNonePos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize {1458pub fn findNonePos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize {
1416 if (start_index >= slice.len) return null;1459 if (start_index >= slice.len) return null;
1417 outer: for (slice[start_index..], start_index..) |c, i| {1460 outer: for (slice[start_index..], start_index..) |c, i| {
1418 for (values) |value| {1461 for (values) |value| {
...@@ -1423,29 +1466,24 @@ pub fn indexOfNonePos(comptime T: type, slice: []const T, start_index: usize, va...@@ -1423,29 +1466,24 @@ pub fn indexOfNonePos(comptime T: type, slice: []const T, start_index: usize, va
1423 return null;1466 return null;
1424}1467}
14251468
1426test indexOfNone {1469/// Deprecated in favor of `find`.
1427 try testing.expect(indexOfNone(u8, "abc123", "123").? == 0);1470pub const indexOf = find;
1428 try testing.expect(lastIndexOfNone(u8, "abc123", "123").? == 2);
1429 try testing.expect(indexOfNone(u8, "123abc", "123").? == 3);
1430 try testing.expect(lastIndexOfNone(u8, "123abc", "123").? == 5);
1431 try testing.expect(indexOfNone(u8, "123123", "123") == null);
1432 try testing.expect(indexOfNone(u8, "333333", "123") == null);
1433
1434 try testing.expect(indexOfNonePos(u8, "abc123", 3, "321") == null);
1435}
14361471
1437/// Search for needle in haystack and return the index of the first occurrence.1472/// Search for needle in haystack and return the index of the first occurrence.
1438/// Uses Boyer-Moore-Horspool algorithm on large inputs; linear search on small inputs.1473/// Uses Boyer-Moore-Horspool algorithm on large inputs; linear search on small inputs.
1439/// Returns null if needle is not found.1474/// Returns null if needle is not found.
1440pub fn indexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize {1475pub fn find(comptime T: type, haystack: []const T, needle: []const T) ?usize {
1441 return indexOfPos(T, haystack, 0, needle);1476 return indexOfPos(T, haystack, 0, needle);
1442}1477}
14431478
1479/// Deprecated in favor of `findLastLinear`.
1480pub const lastIndexOfLinear = findLastLinear;
1481
1444/// Find the index in a slice of a sub-slice, searching from the end backwards.1482/// Find the index in a slice of a sub-slice, searching from the end backwards.
1445/// To start looking at a different index, slice the haystack first.1483/// To start looking at a different index, slice the haystack first.
1446/// Consider using `lastIndexOf` instead of this, which will automatically use a1484/// Consider using `lastIndexOf` instead of this, which will automatically use a
1447/// more sophisticated algorithm on larger inputs.1485/// more sophisticated algorithm on larger inputs.
1448pub fn lastIndexOfLinear(comptime T: type, haystack: []const T, needle: []const T) ?usize {1486pub fn findLastLinear(comptime T: type, haystack: []const T, needle: []const T) ?usize {
1449 if (needle.len > haystack.len) return null;1487 if (needle.len > haystack.len) return null;
1450 var i: usize = haystack.len - needle.len;1488 var i: usize = haystack.len - needle.len;
1451 while (true) : (i -= 1) {1489 while (true) : (i -= 1) {
...@@ -1454,9 +1492,11 @@ pub fn lastIndexOfLinear(comptime T: type, haystack: []const T, needle: []const...@@ -1454,9 +1492,11 @@ pub fn lastIndexOfLinear(comptime T: type, haystack: []const T, needle: []const
1454 }1492 }
1455}1493}
14561494
1495pub const indexOfPosLinear = findPosLinear;
1496
1457/// Consider using `indexOfPos` instead of this, which will automatically use a1497/// Consider using `indexOfPos` instead of this, which will automatically use a
1458/// more sophisticated algorithm on larger inputs.1498/// more sophisticated algorithm on larger inputs.
1459pub fn indexOfPosLinear(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize {1499pub fn findPosLinear(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize {
1460 if (needle.len > haystack.len) return null;1500 if (needle.len > haystack.len) return null;
1461 var i: usize = start_index;1501 var i: usize = start_index;
1462 const end = haystack.len - needle.len;1502 const end = haystack.len - needle.len;
...@@ -1466,24 +1506,24 @@ pub fn indexOfPosLinear(comptime T: type, haystack: []const T, start_index: usiz...@@ -1466,24 +1506,24 @@ pub fn indexOfPosLinear(comptime T: type, haystack: []const T, start_index: usiz
1466 return null;1506 return null;
1467}1507}
14681508
1469test indexOfPosLinear {1509test findPosLinear {
1470 try testing.expectEqual(0, indexOfPosLinear(u8, "", 0, ""));1510 try testing.expectEqual(0, findPosLinear(u8, "", 0, ""));
1471 try testing.expectEqual(0, indexOfPosLinear(u8, "123", 0, ""));1511 try testing.expectEqual(0, findPosLinear(u8, "123", 0, ""));
14721512
1473 try testing.expectEqual(null, indexOfPosLinear(u8, "", 0, "1"));1513 try testing.expectEqual(null, findPosLinear(u8, "", 0, "1"));
1474 try testing.expectEqual(0, indexOfPosLinear(u8, "1", 0, "1"));1514 try testing.expectEqual(0, findPosLinear(u8, "1", 0, "1"));
1475 try testing.expectEqual(null, indexOfPosLinear(u8, "2", 0, "1"));1515 try testing.expectEqual(null, findPosLinear(u8, "2", 0, "1"));
1476 try testing.expectEqual(1, indexOfPosLinear(u8, "21", 0, "1"));1516 try testing.expectEqual(1, findPosLinear(u8, "21", 0, "1"));
1477 try testing.expectEqual(null, indexOfPosLinear(u8, "222", 0, "1"));1517 try testing.expectEqual(null, findPosLinear(u8, "222", 0, "1"));
14781518
1479 try testing.expectEqual(null, indexOfPosLinear(u8, "", 0, "12"));1519 try testing.expectEqual(null, findPosLinear(u8, "", 0, "12"));
1480 try testing.expectEqual(null, indexOfPosLinear(u8, "1", 0, "12"));1520 try testing.expectEqual(null, findPosLinear(u8, "1", 0, "12"));
1481 try testing.expectEqual(null, indexOfPosLinear(u8, "2", 0, "12"));1521 try testing.expectEqual(null, findPosLinear(u8, "2", 0, "12"));
1482 try testing.expectEqual(0, indexOfPosLinear(u8, "12", 0, "12"));1522 try testing.expectEqual(0, findPosLinear(u8, "12", 0, "12"));
1483 try testing.expectEqual(null, indexOfPosLinear(u8, "21", 0, "12"));1523 try testing.expectEqual(null, findPosLinear(u8, "21", 0, "12"));
1484 try testing.expectEqual(1, indexOfPosLinear(u8, "212", 0, "12"));1524 try testing.expectEqual(1, findPosLinear(u8, "212", 0, "12"));
1485 try testing.expectEqual(0, indexOfPosLinear(u8, "122", 0, "12"));1525 try testing.expectEqual(0, findPosLinear(u8, "122", 0, "12"));
1486 try testing.expectEqual(1, indexOfPosLinear(u8, "212112", 0, "12"));1526 try testing.expectEqual(1, findPosLinear(u8, "212112", 0, "12"));
1487}1527}
14881528
1489fn boyerMooreHorspoolPreprocessReverse(pattern: []const u8, table: *[256]usize) void {1529fn boyerMooreHorspoolPreprocessReverse(pattern: []const u8, table: *[256]usize) void {
...@@ -1512,11 +1552,14 @@ fn boyerMooreHorspoolPreprocess(pattern: []const u8, table: *[256]usize) void {...@@ -1512,11 +1552,14 @@ fn boyerMooreHorspoolPreprocess(pattern: []const u8, table: *[256]usize) void {
1512 }1552 }
1513}1553}
15141554
1555/// Deprecated in favor of `find`.
1556pub const lastIndexOf = findLast;
1557
1515/// Find the index in a slice of a sub-slice, searching from the end backwards.1558/// Find the index in a slice of a sub-slice, searching from the end backwards.
1516/// To start looking at a different index, slice the haystack first.1559/// To start looking at a different index, slice the haystack first.
1517/// Uses the Reverse Boyer-Moore-Horspool algorithm on large inputs;1560/// Uses the Reverse Boyer-Moore-Horspool algorithm on large inputs;
1518/// `lastIndexOfLinear` on small inputs.1561/// `lastIndexOfLinear` on small inputs.
1519pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize {1562pub fn findLast(comptime T: type, haystack: []const T, needle: []const T) ?usize {
1520 if (needle.len > haystack.len) return null;1563 if (needle.len > haystack.len) return null;
1521 if (needle.len == 0) return haystack.len;1564 if (needle.len == 0) return haystack.len;
15221565
...@@ -1542,8 +1585,11 @@ pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?us...@@ -1542,8 +1585,11 @@ pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?us
1542 return null;1585 return null;
1543}1586}
15441587
1588/// Deprecated in favor of `findPos`.
1589pub const indexOfPos = findPos;
1590
1545/// Uses Boyer-Moore-Horspool algorithm on large inputs; `indexOfPosLinear` on small inputs.1591/// Uses Boyer-Moore-Horspool algorithm on large inputs; `indexOfPosLinear` on small inputs.
1546pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize {1592pub fn findPos(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize {
1547 if (needle.len > haystack.len) return null;1593 if (needle.len > haystack.len) return null;
1548 if (needle.len < 2) {1594 if (needle.len < 2) {
1549 if (needle.len == 0) return start_index;1595 if (needle.len == 0) return start_index;
...@@ -1593,7 +1639,7 @@ test indexOf {...@@ -1593,7 +1639,7 @@ test indexOf {
1593 try testing.expect(indexOf(u8, "foo foo", "foo").? == 0);1639 try testing.expect(indexOf(u8, "foo foo", "foo").? == 0);
1594 try testing.expect(lastIndexOf(u8, "foo foo", "foo").? == 4);1640 try testing.expect(lastIndexOf(u8, "foo foo", "foo").? == 4);
1595 try testing.expect(lastIndexOfAny(u8, "boo, cat", "abo").? == 6);1641 try testing.expect(lastIndexOfAny(u8, "boo, cat", "abo").? == 6);
1596 try testing.expect(lastIndexOfScalar(u8, "boo", 'o').? == 2);1642 try testing.expect(findScalarLast(u8, "boo", 'o').? == 2);
1597}1643}
15981644
1599test "indexOf multibyte" {1645test "indexOf multibyte" {
...@@ -3079,6 +3125,101 @@ test endsWith {...@@ -3079,6 +3125,101 @@ test endsWith {
3079 try testing.expect(!endsWith(u8, "Bob", "Bo"));3125 try testing.expect(!endsWith(u8, "Bob", "Bo"));
3080}3126}
30813127
3128/// If `slice` starts with `prefix`, returns the rest of `slice` starting at `prefix.len`.
3129pub fn cutPrefix(comptime T: type, slice: []const T, prefix: []const T) ?[]const T {
3130 return if (startsWith(T, slice, prefix)) slice[prefix.len..] else null;
3131}
3132
3133test cutPrefix {
3134 try testing.expectEqualStrings("foo", cutPrefix(u8, "--example=foo", "--example=").?);
3135 try testing.expectEqual(null, cutPrefix(u8, "--example=foo", "-example="));
3136}
3137
3138/// If `slice` ends with `suffix`, returns `slice` from beginning to start of `suffix`.
3139pub fn cutSuffix(comptime T: type, slice: []const T, suffix: []const T) ?[]const T {
3140 return if (endsWith(T, slice, suffix)) slice[0 .. slice.len - suffix.len] else null;
3141}
3142
3143test cutSuffix {
3144 try testing.expectEqualStrings("foo", cutSuffix(u8, "foobar", "bar").?);
3145 try testing.expectEqual(null, cutSuffix(u8, "foobar", "baz"));
3146}
3147
3148/// Returns slice of `haystack` before and after first occurrence of `needle`,
3149/// or `null` if not found.
3150///
3151/// See also:
3152/// * `cutScalar`
3153/// * `split`
3154/// * `tokenizeAny`
3155pub fn cut(comptime T: type, haystack: []const T, needle: []const T) ?struct { []const T, []const T } {
3156 const index = find(T, haystack, needle) orelse return null;
3157 return .{ haystack[0..index], haystack[index + needle.len ..] };
3158}
3159
3160test cut {
3161 try testing.expectEqual(null, cut(u8, "a b c", "B"));
3162 const before, const after = cut(u8, "a be c", "be") orelse return error.TestFailed;
3163 try testing.expectEqualStrings("a ", before);
3164 try testing.expectEqualStrings(" c", after);
3165}
3166
3167/// Returns slice of `haystack` before and after last occurrence of `needle`,
3168/// or `null` if not found.
3169///
3170/// See also:
3171/// * `cut`
3172/// * `cutScalarLast`
3173pub fn cutLast(comptime T: type, haystack: []const T, needle: []const T) ?struct { []const T, []const T } {
3174 const index = findLast(T, haystack, needle) orelse return null;
3175 return .{ haystack[0..index], haystack[index + needle.len ..] };
3176}
3177
3178test cutLast {
3179 try testing.expectEqual(null, cutLast(u8, "a b c", "B"));
3180 const before, const after = cutLast(u8, "a be c be d", "be") orelse return error.TestFailed;
3181 try testing.expectEqualStrings("a be c ", before);
3182 try testing.expectEqualStrings(" d", after);
3183}
3184
3185/// Returns slice of `haystack` before and after first occurrence `needle`, or
3186/// `null` if not found.
3187///
3188/// See also:
3189/// * `cut`
3190/// * `splitScalar`
3191/// * `tokenizeScalar`
3192pub fn cutScalar(comptime T: type, haystack: []const T, needle: T) ?struct { []const T, []const T } {
3193 const index = findScalar(T, haystack, needle) orelse return null;
3194 return .{ haystack[0..index], haystack[index + 1 ..] };
3195}
3196
3197test cutScalar {
3198 try testing.expectEqual(null, cutScalar(u8, "a b c", 'B'));
3199 const before, const after = cutScalar(u8, "a b c", 'b') orelse return error.TestFailed;
3200 try testing.expectEqualStrings("a ", before);
3201 try testing.expectEqualStrings(" c", after);
3202}
3203
3204/// Returns slice of `haystack` before and after last occurrence of `needle`,
3205/// or `null` if not found.
3206///
3207/// See also:
3208/// * `cut`
3209/// * `splitScalar`
3210/// * `tokenizeScalar`
3211pub fn cutScalarLast(comptime T: type, haystack: []const T, needle: T) ?struct { []const T, []const T } {
3212 const index = findScalarLast(T, haystack, needle) orelse return null;
3213 return .{ haystack[0..index], haystack[index + 1 ..] };
3214}
3215
3216test cutScalarLast {
3217 try testing.expectEqual(null, cutScalarLast(u8, "a b c", 'B'));
3218 const before, const after = cutScalarLast(u8, "a b c b d", 'b') orelse return error.TestFailed;
3219 try testing.expectEqualStrings("a b c ", before);
3220 try testing.expectEqualStrings(" d", after);
3221}
3222
3082/// Delimiter type for tokenization and splitting operations.3223/// Delimiter type for tokenization and splitting operations.
3083pub const DelimiterType = enum { sequence, any, scalar };3224pub const DelimiterType = enum { sequence, any, scalar };
30843225
...@@ -3248,7 +3389,7 @@ pub fn SplitBackwardsIterator(comptime T: type, comptime delimiter_type: Delimit...@@ -3248,7 +3389,7 @@ pub fn SplitBackwardsIterator(comptime T: type, comptime delimiter_type: Delimit
3248 const start = if (switch (delimiter_type) {3389 const start = if (switch (delimiter_type) {
3249 .sequence => lastIndexOf(T, self.buffer[0..end], self.delimiter),3390 .sequence => lastIndexOf(T, self.buffer[0..end], self.delimiter),
3250 .any => lastIndexOfAny(T, self.buffer[0..end], self.delimiter),3391 .any => lastIndexOfAny(T, self.buffer[0..end], self.delimiter),
3251 .scalar => lastIndexOfScalar(T, self.buffer[0..end], self.delimiter),3392 .scalar => findScalarLast(T, self.buffer[0..end], self.delimiter),
3252 }) |delim_start| blk: {3393 }) |delim_start| blk: {
3253 self.index = delim_start;3394 self.index = delim_start;
3254 break :blk delim_start + switch (delimiter_type) {3395 break :blk delim_start + switch (delimiter_type) {
...@@ -3562,9 +3703,12 @@ test minMax {...@@ -3562,9 +3703,12 @@ test minMax {
3562 }3703 }
3563}3704}
35643705
3706/// Deprecated in favor of `findMin`.
3707pub const indexOfMin = findMin;
3708
3565/// Returns the index of the smallest number in a slice. O(n).3709/// Returns the index of the smallest number in a slice. O(n).
3566/// `slice` must not be empty.3710/// `slice` must not be empty.
3567pub fn indexOfMin(comptime T: type, slice: []const T) usize {3711pub fn findMin(comptime T: type, slice: []const T) usize {
3568 assert(slice.len > 0);3712 assert(slice.len > 0);
3569 var best = slice[0];3713 var best = slice[0];
3570 var index: usize = 0;3714 var index: usize = 0;
...@@ -3577,15 +3721,17 @@ pub fn indexOfMin(comptime T: type, slice: []const T) usize {...@@ -3577,15 +3721,17 @@ pub fn indexOfMin(comptime T: type, slice: []const T) usize {
3577 return index;3721 return index;
3578}3722}
35793723
3580test indexOfMin {3724test findMin {
3581 try testing.expectEqual(indexOfMin(u8, "abcdefg"), 0);3725 try testing.expectEqual(findMin(u8, "abcdefg"), 0);
3582 try testing.expectEqual(indexOfMin(u8, "bcdefga"), 6);3726 try testing.expectEqual(findMin(u8, "bcdefga"), 6);
3583 try testing.expectEqual(indexOfMin(u8, "a"), 0);3727 try testing.expectEqual(findMin(u8, "a"), 0);
3584}3728}
35853729
3730pub const indexOfMax = findMax;
3731
3586/// Returns the index of the largest number in a slice. O(n).3732/// Returns the index of the largest number in a slice. O(n).
3587/// `slice` must not be empty.3733/// `slice` must not be empty.
3588pub fn indexOfMax(comptime T: type, slice: []const T) usize {3734pub fn findMax(comptime T: type, slice: []const T) usize {
3589 assert(slice.len > 0);3735 assert(slice.len > 0);
3590 var best = slice[0];3736 var best = slice[0];
3591 var index: usize = 0;3737 var index: usize = 0;
...@@ -3598,16 +3744,19 @@ pub fn indexOfMax(comptime T: type, slice: []const T) usize {...@@ -3598,16 +3744,19 @@ pub fn indexOfMax(comptime T: type, slice: []const T) usize {
3598 return index;3744 return index;
3599}3745}
36003746
3601test indexOfMax {3747test findMax {
3602 try testing.expectEqual(indexOfMax(u8, "abcdefg"), 6);3748 try testing.expectEqual(findMax(u8, "abcdefg"), 6);
3603 try testing.expectEqual(indexOfMax(u8, "gabcdef"), 0);3749 try testing.expectEqual(findMax(u8, "gabcdef"), 0);
3604 try testing.expectEqual(indexOfMax(u8, "a"), 0);3750 try testing.expectEqual(findMax(u8, "a"), 0);
3605}3751}
36063752
3753/// Deprecated in favor of `findMinMax`.
3754pub const indexOfMinMax = findMinMax;
3755
3607/// Finds the indices of the smallest and largest number in a slice. O(n).3756/// Finds the indices of the smallest and largest number in a slice. O(n).
3608/// Returns the indices of the smallest and largest numbers in that order.3757/// Returns the indices of the smallest and largest numbers in that order.
3609/// `slice` must not be empty.3758/// `slice` must not be empty.
3610pub fn indexOfMinMax(comptime T: type, slice: []const T) struct { usize, usize } {3759pub fn findMinMax(comptime T: type, slice: []const T) struct { usize, usize } {
3611 assert(slice.len > 0);3760 assert(slice.len > 0);
3612 var minVal = slice[0];3761 var minVal = slice[0];
3613 var maxVal = slice[0];3762 var maxVal = slice[0];
...@@ -3626,10 +3775,10 @@ pub fn indexOfMinMax(comptime T: type, slice: []const T) struct { usize, usize }...@@ -3626,10 +3775,10 @@ pub fn indexOfMinMax(comptime T: type, slice: []const T) struct { usize, usize }
3626 return .{ minIdx, maxIdx };3775 return .{ minIdx, maxIdx };
3627}3776}
36283777
3629test indexOfMinMax {3778test findMinMax {
3630 try testing.expectEqual(.{ 0, 6 }, indexOfMinMax(u8, "abcdefg"));3779 try testing.expectEqual(.{ 0, 6 }, findMinMax(u8, "abcdefg"));
3631 try testing.expectEqual(.{ 1, 0 }, indexOfMinMax(u8, "gabcdef"));3780 try testing.expectEqual(.{ 1, 0 }, findMinMax(u8, "gabcdef"));
3632 try testing.expectEqual(.{ 0, 0 }, indexOfMinMax(u8, "a"));3781 try testing.expectEqual(.{ 0, 0 }, findMinMax(u8, "a"));
3633}3782}
36343783
3635/// Exchanges contents of two memory locations.3784/// Exchanges contents of two memory locations.
src/main.zig+107-132
...@@ -1022,10 +1022,9 @@ fn buildOutputType(...@@ -1022,10 +1022,9 @@ fn buildOutputType(
10221022
1023 var file_ext: ?Compilation.FileExt = null;1023 var file_ext: ?Compilation.FileExt = null;
1024 args_loop: while (args_iter.next()) |arg| {1024 args_loop: while (args_iter.next()) |arg| {
1025 if (mem.startsWith(u8, arg, "@")) {1025 if (mem.cutPrefix(u8, arg, "@")) |resp_file_path| {
1026 // This is a "compiler response file". We must parse the file and treat its1026 // This is a "compiler response file". We must parse the file and treat its
1027 // contents as command line parameters.1027 // contents as command line parameters.
1028 const resp_file_path = arg[1..];
1029 args_iter.resp_file = initArgIteratorResponseFile(arena, resp_file_path) catch |err| {1028 args_iter.resp_file = initArgIteratorResponseFile(arena, resp_file_path) catch |err| {
1030 fatal("unable to read response file '{s}': {s}", .{ resp_file_path, @errorName(err) });1029 fatal("unable to read response file '{s}': {s}", .{ resp_file_path, @errorName(err) });
1031 };1030 };
...@@ -1043,9 +1042,8 @@ fn buildOutputType(...@@ -1043,9 +1042,8 @@ fn buildOutputType(
1043 fatal("unexpected end-of-parameter mark: --", .{});1042 fatal("unexpected end-of-parameter mark: --", .{});
1044 }1043 }
1045 } else if (mem.eql(u8, arg, "--dep")) {1044 } else if (mem.eql(u8, arg, "--dep")) {
1046 var it = mem.splitScalar(u8, args_iter.nextOrFatal(), '=');1045 const next_arg = args_iter.nextOrFatal();
1047 const key = it.first();1046 const key, const value = mem.cutScalar(u8, next_arg, '=') orelse .{ next_arg, next_arg };
1048 const value = if (it.peek() != null) it.rest() else key;
1049 if (mem.eql(u8, key, "std") and !mem.eql(u8, value, "std")) {1047 if (mem.eql(u8, key, "std") and !mem.eql(u8, value, "std")) {
1050 fatal("unable to import as '{s}': conflicts with builtin module", .{1048 fatal("unable to import as '{s}': conflicts with builtin module", .{
1051 key,1049 key,
...@@ -1062,10 +1060,8 @@ fn buildOutputType(...@@ -1062,10 +1060,8 @@ fn buildOutputType(
1062 .key = key,1060 .key = key,
1063 .value = value,1061 .value = value,
1064 });1062 });
1065 } else if (mem.startsWith(u8, arg, "-M")) {1063 } else if (mem.cutPrefix(u8, arg, "-M")) |rest| {
1066 var it = mem.splitScalar(u8, arg["-M".len..], '=');1064 const mod_name, const root_src_orig = mem.cutScalar(u8, rest, '=') orelse .{ rest, null };
1067 const mod_name = it.first();
1068 const root_src_orig = if (it.peek() != null) it.rest() else null;
1069 try handleModArg(1065 try handleModArg(
1070 arena,1066 arena,
1071 mod_name,1067 mod_name,
...@@ -1096,8 +1092,8 @@ fn buildOutputType(...@@ -1096,8 +1092,8 @@ fn buildOutputType(
1096 }1092 }
1097 } else if (mem.eql(u8, arg, "-rcincludes")) {1093 } else if (mem.eql(u8, arg, "-rcincludes")) {
1098 rc_includes = parseRcIncludes(args_iter.nextOrFatal());1094 rc_includes = parseRcIncludes(args_iter.nextOrFatal());
1099 } else if (mem.startsWith(u8, arg, "-rcincludes=")) {1095 } else if (mem.cutPrefix(u8, arg, "-rcincludes=")) |rest| {
1100 rc_includes = parseRcIncludes(arg["-rcincludes=".len..]);1096 rc_includes = parseRcIncludes(rest);
1101 } else if (mem.eql(u8, arg, "-rcflags")) {1097 } else if (mem.eql(u8, arg, "-rcflags")) {
1102 extra_rcflags.shrinkRetainingCapacity(0);1098 extra_rcflags.shrinkRetainingCapacity(0);
1103 while (true) {1099 while (true) {
...@@ -1107,9 +1103,9 @@ fn buildOutputType(...@@ -1107,9 +1103,9 @@ fn buildOutputType(
1107 if (mem.eql(u8, next_arg, "--")) break;1103 if (mem.eql(u8, next_arg, "--")) break;
1108 try extra_rcflags.append(arena, next_arg);1104 try extra_rcflags.append(arena, next_arg);
1109 }1105 }
1110 } else if (mem.startsWith(u8, arg, "-fstructured-cfg")) {1106 } else if (mem.eql(u8, arg, "-fstructured-cfg")) {
1111 mod_opts.structured_cfg = true;1107 mod_opts.structured_cfg = true;
1112 } else if (mem.startsWith(u8, arg, "-fno-structured-cfg")) {1108 } else if (mem.eql(u8, arg, "-fno-structured-cfg")) {
1113 mod_opts.structured_cfg = false;1109 mod_opts.structured_cfg = false;
1114 } else if (mem.eql(u8, arg, "--color")) {1110 } else if (mem.eql(u8, arg, "--color")) {
1115 const next_arg = args_iter.next() orelse {1111 const next_arg = args_iter.next() orelse {
...@@ -1118,8 +1114,7 @@ fn buildOutputType(...@@ -1118,8 +1114,7 @@ fn buildOutputType(
1118 color = std.meta.stringToEnum(Color, next_arg) orelse {1114 color = std.meta.stringToEnum(Color, next_arg) orelse {
1119 fatal("expected [auto|on|off] after --color, found '{s}'", .{next_arg});1115 fatal("expected [auto|on|off] after --color, found '{s}'", .{next_arg});
1120 };1116 };
1121 } else if (mem.startsWith(u8, arg, "-j")) {1117 } else if (mem.cutPrefix(u8, arg, "-j")) |str| {
1122 const str = arg["-j".len..];
1123 const num = std.fmt.parseUnsigned(u32, str, 10) catch |err| {1118 const num = std.fmt.parseUnsigned(u32, str, 10) catch |err| {
1124 fatal("unable to parse jobs count '{s}': {s}", .{1119 fatal("unable to parse jobs count '{s}': {s}", .{
1125 str, @errorName(err),1120 str, @errorName(err),
...@@ -1133,8 +1128,8 @@ fn buildOutputType(...@@ -1133,8 +1128,8 @@ fn buildOutputType(
1133 subsystem = try parseSubSystem(args_iter.nextOrFatal());1128 subsystem = try parseSubSystem(args_iter.nextOrFatal());
1134 } else if (mem.eql(u8, arg, "-O")) {1129 } else if (mem.eql(u8, arg, "-O")) {
1135 mod_opts.optimize_mode = parseOptimizeMode(args_iter.nextOrFatal());1130 mod_opts.optimize_mode = parseOptimizeMode(args_iter.nextOrFatal());
1136 } else if (mem.startsWith(u8, arg, "-fentry=")) {1131 } else if (mem.cutPrefix(u8, arg, "-fentry=")) |rest| {
1137 entry = .{ .named = arg["-fentry=".len..] };1132 entry = .{ .named = rest };
1138 } else if (mem.eql(u8, arg, "--force_undefined")) {1133 } else if (mem.eql(u8, arg, "--force_undefined")) {
1139 try force_undefined_symbols.put(arena, args_iter.nextOrFatal(), {});1134 try force_undefined_symbols.put(arena, args_iter.nextOrFatal(), {});
1140 } else if (mem.eql(u8, arg, "--discard-all")) {1135 } else if (mem.eql(u8, arg, "--discard-all")) {
...@@ -1161,8 +1156,7 @@ fn buildOutputType(...@@ -1161,8 +1156,7 @@ fn buildOutputType(
1161 try create_module.frameworks.put(arena, args_iter.nextOrFatal(), .{ .needed = true });1156 try create_module.frameworks.put(arena, args_iter.nextOrFatal(), .{ .needed = true });
1162 } else if (mem.eql(u8, arg, "-install_name")) {1157 } else if (mem.eql(u8, arg, "-install_name")) {
1163 install_name = args_iter.nextOrFatal();1158 install_name = args_iter.nextOrFatal();
1164 } else if (mem.startsWith(u8, arg, "--compress-debug-sections=")) {1159 } else if (mem.cutPrefix(u8, arg, "--compress-debug-sections=")) |param| {
1165 const param = arg["--compress-debug-sections=".len..];
1166 linker_compress_debug_sections = std.meta.stringToEnum(link.File.Lld.Elf.CompressDebugSections, param) orelse {1160 linker_compress_debug_sections = std.meta.stringToEnum(link.File.Lld.Elf.CompressDebugSections, param) orelse {
1167 fatal("expected --compress-debug-sections=[none|zlib|zstd], found '{s}'", .{param});1161 fatal("expected --compress-debug-sections=[none|zlib|zstd], found '{s}'", .{param});
1168 };1162 };
...@@ -1260,8 +1254,8 @@ fn buildOutputType(...@@ -1260,8 +1254,8 @@ fn buildOutputType(
1260 try cc_argv.appendSlice(arena, &.{ arg, args_iter.nextOrFatal() });1254 try cc_argv.appendSlice(arena, &.{ arg, args_iter.nextOrFatal() });
1261 } else if (mem.eql(u8, arg, "-I")) {1255 } else if (mem.eql(u8, arg, "-I")) {
1262 try cssan.addIncludePath(arena, &cc_argv, .I, arg, args_iter.nextOrFatal(), false);1256 try cssan.addIncludePath(arena, &cc_argv, .I, arg, args_iter.nextOrFatal(), false);
1263 } else if (mem.startsWith(u8, arg, "--embed-dir=")) {1257 } else if (mem.cutPrefix(u8, arg, "--embed-dir=")) |rest| {
1264 try cssan.addIncludePath(arena, &cc_argv, .embed_dir, arg, arg["--embed-dir=".len..], true);1258 try cssan.addIncludePath(arena, &cc_argv, .embed_dir, arg, rest, true);
1265 } else if (mem.eql(u8, arg, "-isystem")) {1259 } else if (mem.eql(u8, arg, "-isystem")) {
1266 try cssan.addIncludePath(arena, &cc_argv, .isystem, arg, args_iter.nextOrFatal(), false);1260 try cssan.addIncludePath(arena, &cc_argv, .isystem, arg, args_iter.nextOrFatal(), false);
1267 } else if (mem.eql(u8, arg, "-iwithsysroot")) {1261 } else if (mem.eql(u8, arg, "-iwithsysroot")) {
...@@ -1288,14 +1282,14 @@ fn buildOutputType(...@@ -1288,14 +1282,14 @@ fn buildOutputType(
1288 target_mcpu = args_iter.nextOrFatal();1282 target_mcpu = args_iter.nextOrFatal();
1289 } else if (mem.eql(u8, arg, "-mcmodel")) {1283 } else if (mem.eql(u8, arg, "-mcmodel")) {
1290 mod_opts.code_model = parseCodeModel(args_iter.nextOrFatal());1284 mod_opts.code_model = parseCodeModel(args_iter.nextOrFatal());
1291 } else if (mem.startsWith(u8, arg, "-mcmodel=")) {1285 } else if (mem.cutPrefix(u8, arg, "-mcmodel=")) |rest| {
1292 mod_opts.code_model = parseCodeModel(arg["-mcmodel=".len..]);1286 mod_opts.code_model = parseCodeModel(rest);
1293 } else if (mem.startsWith(u8, arg, "-ofmt=")) {1287 } else if (mem.cutPrefix(u8, arg, "-ofmt=")) |rest| {
1294 create_module.object_format = arg["-ofmt=".len..];1288 create_module.object_format = rest;
1295 } else if (mem.startsWith(u8, arg, "-mcpu=")) {1289 } else if (mem.cutPrefix(u8, arg, "-mcpu=")) |rest| {
1296 target_mcpu = arg["-mcpu=".len..];1290 target_mcpu = rest;
1297 } else if (mem.startsWith(u8, arg, "-O")) {1291 } else if (mem.cutPrefix(u8, arg, "-O")) |rest| {
1298 mod_opts.optimize_mode = parseOptimizeMode(arg["-O".len..]);1292 mod_opts.optimize_mode = parseOptimizeMode(rest);
1299 } else if (mem.eql(u8, arg, "--dynamic-linker")) {1293 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
1300 create_module.dynamic_linker = args_iter.nextOrFatal();1294 create_module.dynamic_linker = args_iter.nextOrFatal();
1301 } else if (mem.eql(u8, arg, "--sysroot")) {1295 } else if (mem.eql(u8, arg, "--sysroot")) {
...@@ -1331,9 +1325,7 @@ fn buildOutputType(...@@ -1331,9 +1325,7 @@ fn buildOutputType(
1331 } else {1325 } else {
1332 dev.check(.network_listen);1326 dev.check(.network_listen);
1333 // example: --listen 127.0.0.1:90001327 // example: --listen 127.0.0.1:9000
1334 var it = std.mem.splitScalar(u8, next_arg, ':');1328 const host, const port_text = mem.cutScalar(u8, next_arg, ':') orelse .{ next_arg, "14735" };
1335 const host = it.next().?;
1336 const port_text = it.next() orelse "14735";
1337 const port = std.fmt.parseInt(u16, port_text, 10) catch |err|1329 const port = std.fmt.parseInt(u16, port_text, 10) catch |err|
1338 fatal("invalid port number: '{s}': {s}", .{ port_text, @errorName(err) });1330 fatal("invalid port number: '{s}': {s}", .{ port_text, @errorName(err) });
1339 listen = .{ .ip4 = std.net.Ip4Address.parse(host, port) catch |err|1331 listen = .{ .ip4 = std.net.Ip4Address.parse(host, port) catch |err|
...@@ -1393,8 +1385,7 @@ fn buildOutputType(...@@ -1393,8 +1385,7 @@ fn buildOutputType(
1393 create_module.opts.pie = false;1385 create_module.opts.pie = false;
1394 } else if (mem.eql(u8, arg, "-flto")) {1386 } else if (mem.eql(u8, arg, "-flto")) {
1395 create_module.opts.lto = .full;1387 create_module.opts.lto = .full;
1396 } else if (mem.startsWith(u8, arg, "-flto=")) {1388 } else if (mem.cutPrefix(u8, arg, "-flto=")) |mode| {
1397 const mode = arg["-flto=".len..];
1398 if (mem.eql(u8, mode, "full")) {1389 if (mem.eql(u8, mode, "full")) {
1399 create_module.opts.lto = .full;1390 create_module.opts.lto = .full;
1400 } else if (mem.eql(u8, mode, "thin")) {1391 } else if (mem.eql(u8, mode, "thin")) {
...@@ -1428,8 +1419,7 @@ fn buildOutputType(...@@ -1428,8 +1419,7 @@ fn buildOutputType(
1428 mod_opts.omit_frame_pointer = false;1419 mod_opts.omit_frame_pointer = false;
1429 } else if (mem.eql(u8, arg, "-fsanitize-c")) {1420 } else if (mem.eql(u8, arg, "-fsanitize-c")) {
1430 mod_opts.sanitize_c = .full;1421 mod_opts.sanitize_c = .full;
1431 } else if (mem.startsWith(u8, arg, "-fsanitize-c=")) {1422 } else if (mem.cutPrefix(u8, arg, "-fsanitize-c=")) |mode| {
1432 const mode = arg["-fsanitize-c=".len..];
1433 if (mem.eql(u8, mode, "trap")) {1423 if (mem.eql(u8, mode, "trap")) {
1434 mod_opts.sanitize_c = .trap;1424 mod_opts.sanitize_c = .trap;
1435 } else if (mem.eql(u8, mode, "full")) {1425 } else if (mem.eql(u8, mode, "full")) {
...@@ -1477,8 +1467,7 @@ fn buildOutputType(...@@ -1477,8 +1467,7 @@ fn buildOutputType(
1477 create_module.opts.san_cov_trace_pc_guard = false;1467 create_module.opts.san_cov_trace_pc_guard = false;
1478 } else if (mem.eql(u8, arg, "-freference-trace")) {1468 } else if (mem.eql(u8, arg, "-freference-trace")) {
1479 reference_trace = 256;1469 reference_trace = 256;
1480 } else if (mem.startsWith(u8, arg, "-freference-trace=")) {1470 } else if (mem.cutPrefix(u8, arg, "-freference-trace=")) |num| {
1481 const num = arg["-freference-trace=".len..];
1482 reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {1471 reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
1483 fatal("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) });1472 fatal("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) });
1484 };1473 };
...@@ -1492,51 +1481,51 @@ fn buildOutputType(...@@ -1492,51 +1481,51 @@ fn buildOutputType(
1492 create_module.opts.rdynamic = true;1481 create_module.opts.rdynamic = true;
1493 } else if (mem.eql(u8, arg, "-fsoname")) {1482 } else if (mem.eql(u8, arg, "-fsoname")) {
1494 soname = .yes_default_value;1483 soname = .yes_default_value;
1495 } else if (mem.startsWith(u8, arg, "-fsoname=")) {1484 } else if (mem.cutPrefix(u8, arg, "-fsoname=")) |rest| {
1496 soname = .{ .yes = arg["-fsoname=".len..] };1485 soname = .{ .yes = rest };
1497 } else if (mem.eql(u8, arg, "-fno-soname")) {1486 } else if (mem.eql(u8, arg, "-fno-soname")) {
1498 soname = .no;1487 soname = .no;
1499 } else if (mem.eql(u8, arg, "-femit-bin")) {1488 } else if (mem.eql(u8, arg, "-femit-bin")) {
1500 emit_bin = .yes_default_path;1489 emit_bin = .yes_default_path;
1501 } else if (mem.startsWith(u8, arg, "-femit-bin=")) {1490 } else if (mem.cutPrefix(u8, arg, "-femit-bin=")) |rest| {
1502 emit_bin = .{ .yes = arg["-femit-bin=".len..] };1491 emit_bin = .{ .yes = rest };
1503 } else if (mem.eql(u8, arg, "-fno-emit-bin")) {1492 } else if (mem.eql(u8, arg, "-fno-emit-bin")) {
1504 emit_bin = .no;1493 emit_bin = .no;
1505 } else if (mem.eql(u8, arg, "-femit-h")) {1494 } else if (mem.eql(u8, arg, "-femit-h")) {
1506 emit_h = .yes_default_path;1495 emit_h = .yes_default_path;
1507 } else if (mem.startsWith(u8, arg, "-femit-h=")) {1496 } else if (mem.cutPrefix(u8, arg, "-femit-h=")) |rest| {
1508 emit_h = .{ .yes = arg["-femit-h=".len..] };1497 emit_h = .{ .yes = rest };
1509 } else if (mem.eql(u8, arg, "-fno-emit-h")) {1498 } else if (mem.eql(u8, arg, "-fno-emit-h")) {
1510 emit_h = .no;1499 emit_h = .no;
1511 } else if (mem.eql(u8, arg, "-femit-asm")) {1500 } else if (mem.eql(u8, arg, "-femit-asm")) {
1512 emit_asm = .yes_default_path;1501 emit_asm = .yes_default_path;
1513 } else if (mem.startsWith(u8, arg, "-femit-asm=")) {1502 } else if (mem.cutPrefix(u8, arg, "-femit-asm=")) |rest| {
1514 emit_asm = .{ .yes = arg["-femit-asm=".len..] };1503 emit_asm = .{ .yes = rest };
1515 } else if (mem.eql(u8, arg, "-fno-emit-asm")) {1504 } else if (mem.eql(u8, arg, "-fno-emit-asm")) {
1516 emit_asm = .no;1505 emit_asm = .no;
1517 } else if (mem.eql(u8, arg, "-femit-llvm-ir")) {1506 } else if (mem.eql(u8, arg, "-femit-llvm-ir")) {
1518 emit_llvm_ir = .yes_default_path;1507 emit_llvm_ir = .yes_default_path;
1519 } else if (mem.startsWith(u8, arg, "-femit-llvm-ir=")) {1508 } else if (mem.cutPrefix(u8, arg, "-femit-llvm-ir=")) |rest| {
1520 emit_llvm_ir = .{ .yes = arg["-femit-llvm-ir=".len..] };1509 emit_llvm_ir = .{ .yes = rest };
1521 } else if (mem.eql(u8, arg, "-fno-emit-llvm-ir")) {1510 } else if (mem.eql(u8, arg, "-fno-emit-llvm-ir")) {
1522 emit_llvm_ir = .no;1511 emit_llvm_ir = .no;
1523 } else if (mem.eql(u8, arg, "-femit-llvm-bc")) {1512 } else if (mem.eql(u8, arg, "-femit-llvm-bc")) {
1524 emit_llvm_bc = .yes_default_path;1513 emit_llvm_bc = .yes_default_path;
1525 } else if (mem.startsWith(u8, arg, "-femit-llvm-bc=")) {1514 } else if (mem.cutPrefix(u8, arg, "-femit-llvm-bc=")) |rest| {
1526 emit_llvm_bc = .{ .yes = arg["-femit-llvm-bc=".len..] };1515 emit_llvm_bc = .{ .yes = rest };
1527 } else if (mem.eql(u8, arg, "-fno-emit-llvm-bc")) {1516 } else if (mem.eql(u8, arg, "-fno-emit-llvm-bc")) {
1528 emit_llvm_bc = .no;1517 emit_llvm_bc = .no;
1529 } else if (mem.eql(u8, arg, "-femit-docs")) {1518 } else if (mem.eql(u8, arg, "-femit-docs")) {
1530 emit_docs = .yes_default_path;1519 emit_docs = .yes_default_path;
1531 } else if (mem.startsWith(u8, arg, "-femit-docs=")) {1520 } else if (mem.cutPrefix(u8, arg, "-femit-docs=")) |rest| {
1532 emit_docs = .{ .yes = arg["-femit-docs=".len..] };1521 emit_docs = .{ .yes = rest };
1533 } else if (mem.eql(u8, arg, "-fno-emit-docs")) {1522 } else if (mem.eql(u8, arg, "-fno-emit-docs")) {
1534 emit_docs = .no;1523 emit_docs = .no;
1535 } else if (mem.eql(u8, arg, "-femit-implib")) {1524 } else if (mem.eql(u8, arg, "-femit-implib")) {
1536 emit_implib = .yes_default_path;1525 emit_implib = .yes_default_path;
1537 emit_implib_arg_provided = true;1526 emit_implib_arg_provided = true;
1538 } else if (mem.startsWith(u8, arg, "-femit-implib=")) {1527 } else if (mem.cutPrefix(u8, arg, "-femit-implib=")) |rest| {
1539 emit_implib = .{ .yes = arg["-femit-implib=".len..] };1528 emit_implib = .{ .yes = rest };
1540 emit_implib_arg_provided = true;1529 emit_implib_arg_provided = true;
1541 } else if (mem.eql(u8, arg, "-fno-emit-implib")) {1530 } else if (mem.eql(u8, arg, "-fno-emit-implib")) {
1542 emit_implib = .no;1531 emit_implib = .no;
...@@ -1586,8 +1575,7 @@ fn buildOutputType(...@@ -1586,8 +1575,7 @@ fn buildOutputType(
1586 mod_opts.no_builtin = false;1575 mod_opts.no_builtin = false;
1587 } else if (mem.eql(u8, arg, "-fno-builtin")) {1576 } else if (mem.eql(u8, arg, "-fno-builtin")) {
1588 mod_opts.no_builtin = true;1577 mod_opts.no_builtin = true;
1589 } else if (mem.startsWith(u8, arg, "-fopt-bisect-limit=")) {1578 } else if (mem.cutPrefix(u8, arg, "-fopt-bisect-limit=")) |next_arg| {
1590 const next_arg = arg["-fopt-bisect-limit=".len..];
1591 llvm_opt_bisect_limit = std.fmt.parseInt(c_int, next_arg, 0) catch |err|1579 llvm_opt_bisect_limit = std.fmt.parseInt(c_int, next_arg, 0) catch |err|
1592 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });1580 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
1593 } else if (mem.eql(u8, arg, "--eh-frame-hdr")) {1581 } else if (mem.eql(u8, arg, "--eh-frame-hdr")) {
...@@ -1630,10 +1618,10 @@ fn buildOutputType(...@@ -1630,10 +1618,10 @@ fn buildOutputType(
1630 linker_z_relro = true;1618 linker_z_relro = true;
1631 } else if (mem.eql(u8, z_arg, "norelro")) {1619 } else if (mem.eql(u8, z_arg, "norelro")) {
1632 linker_z_relro = false;1620 linker_z_relro = false;
1633 } else if (mem.startsWith(u8, z_arg, "common-page-size=")) {1621 } else if (prefixedIntArg(z_arg, "common-page-size=")) |int| {
1634 linker_z_common_page_size = parseIntSuffix(z_arg, "common-page-size=".len);1622 linker_z_common_page_size = int;
1635 } else if (mem.startsWith(u8, z_arg, "max-page-size=")) {1623 } else if (prefixedIntArg(z_arg, "max-page-size=")) |int| {
1636 linker_z_max_page_size = parseIntSuffix(z_arg, "max-page-size=".len);1624 linker_z_max_page_size = int;
1637 } else {1625 } else {
1638 fatal("unsupported linker extension flag: -z {s}", .{z_arg});1626 fatal("unsupported linker extension flag: -z {s}", .{z_arg});
1639 }1627 }
...@@ -1654,16 +1642,16 @@ fn buildOutputType(...@@ -1654,16 +1642,16 @@ fn buildOutputType(
1654 linker_import_table = true;1642 linker_import_table = true;
1655 } else if (mem.eql(u8, arg, "--export-table")) {1643 } else if (mem.eql(u8, arg, "--export-table")) {
1656 linker_export_table = true;1644 linker_export_table = true;
1657 } else if (mem.startsWith(u8, arg, "--initial-memory=")) {1645 } else if (prefixedIntArg(arg, "--initial-memory=")) |int| {
1658 linker_initial_memory = parseIntSuffix(arg, "--initial-memory=".len);1646 linker_initial_memory = int;
1659 } else if (mem.startsWith(u8, arg, "--max-memory=")) {1647 } else if (prefixedIntArg(arg, "--max-memory=")) |int| {
1660 linker_max_memory = parseIntSuffix(arg, "--max-memory=".len);1648 linker_max_memory = int;
1661 } else if (mem.eql(u8, arg, "--shared-memory")) {1649 } else if (mem.eql(u8, arg, "--shared-memory")) {
1662 create_module.opts.shared_memory = true;1650 create_module.opts.shared_memory = true;
1663 } else if (mem.startsWith(u8, arg, "--global-base=")) {1651 } else if (prefixedIntArg(arg, "--global-base=")) |int| {
1664 linker_global_base = parseIntSuffix(arg, "--global-base=".len);1652 linker_global_base = int;
1665 } else if (mem.startsWith(u8, arg, "--export=")) {1653 } else if (mem.cutPrefix(u8, arg, "--export=")) |rest| {
1666 try linker_export_symbol_names.append(arena, arg["--export=".len..]);1654 try linker_export_symbol_names.append(arena, rest);
1667 } else if (mem.eql(u8, arg, "-Bsymbolic")) {1655 } else if (mem.eql(u8, arg, "-Bsymbolic")) {
1668 linker_bind_global_refs_locally = true;1656 linker_bind_global_refs_locally = true;
1669 } else if (mem.eql(u8, arg, "--gc-sections")) {1657 } else if (mem.eql(u8, arg, "--gc-sections")) {
...@@ -1672,8 +1660,7 @@ fn buildOutputType(...@@ -1672,8 +1660,7 @@ fn buildOutputType(
1672 linker_gc_sections = false;1660 linker_gc_sections = false;
1673 } else if (mem.eql(u8, arg, "--build-id")) {1661 } else if (mem.eql(u8, arg, "--build-id")) {
1674 build_id = .fast;1662 build_id = .fast;
1675 } else if (mem.startsWith(u8, arg, "--build-id=")) {1663 } else if (mem.cutPrefix(u8, arg, "--build-id=")) |style| {
1676 const style = arg["--build-id=".len..];
1677 build_id = std.zig.BuildId.parse(style) catch |err| {1664 build_id = std.zig.BuildId.parse(style) catch |err| {
1678 fatal("unable to parse --build-id style '{s}': {s}", .{1665 fatal("unable to parse --build-id style '{s}': {s}", .{
1679 style, @errorName(err),1666 style, @errorName(err),
...@@ -1697,26 +1684,26 @@ fn buildOutputType(...@@ -1697,26 +1684,26 @@ fn buildOutputType(
1697 verbose_generic_instances = true;1684 verbose_generic_instances = true;
1698 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {1685 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
1699 verbose_llvm_ir = "-";1686 verbose_llvm_ir = "-";
1700 } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) {1687 } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-ir=")) |rest| {
1701 verbose_llvm_ir = arg["--verbose-llvm-ir=".len..];1688 verbose_llvm_ir = rest;
1702 } else if (mem.startsWith(u8, arg, "--verbose-llvm-bc=")) {1689 } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-bc=")) |rest| {
1703 verbose_llvm_bc = arg["--verbose-llvm-bc=".len..];1690 verbose_llvm_bc = rest;
1704 } else if (mem.eql(u8, arg, "--verbose-cimport")) {1691 } else if (mem.eql(u8, arg, "--verbose-cimport")) {
1705 verbose_cimport = true;1692 verbose_cimport = true;
1706 } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {1693 } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {
1707 verbose_llvm_cpu_features = true;1694 verbose_llvm_cpu_features = true;
1708 } else if (mem.startsWith(u8, arg, "-T")) {1695 } else if (mem.cutPrefix(u8, arg, "-T")) |rest| {
1709 linker_script = arg[2..];1696 linker_script = rest;
1710 } else if (mem.startsWith(u8, arg, "-L")) {1697 } else if (mem.cutPrefix(u8, arg, "-L")) |rest| {
1711 try create_module.lib_dir_args.append(arena, arg[2..]);1698 try create_module.lib_dir_args.append(arena, rest);
1712 } else if (mem.startsWith(u8, arg, "-F")) {1699 } else if (mem.cutPrefix(u8, arg, "-F")) |rest| {
1713 try create_module.framework_dirs.append(arena, arg[2..]);1700 try create_module.framework_dirs.append(arena, rest);
1714 } else if (mem.startsWith(u8, arg, "-l")) {1701 } else if (mem.cutPrefix(u8, arg, "-l")) |name| {
1715 // We don't know whether this library is part of libc1702 // We don't know whether this library is part of libc
1716 // or libc++ until we resolve the target, so we append1703 // or libc++ until we resolve the target, so we append
1717 // to the list for now.1704 // to the list for now.
1718 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{1705 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
1719 .name = arg["-l".len..],1706 .name = name,
1720 .query = .{1707 .query = .{
1721 .needed = false,1708 .needed = false,
1722 .weak = false,1709 .weak = false,
...@@ -1725,9 +1712,9 @@ fn buildOutputType(...@@ -1725,9 +1712,9 @@ fn buildOutputType(
1725 .allow_so_scripts = allow_so_scripts,1712 .allow_so_scripts = allow_so_scripts,
1726 },1713 },
1727 } });1714 } });
1728 } else if (mem.startsWith(u8, arg, "-needed-l")) {1715 } else if (mem.cutPrefix(u8, arg, "-needed-l")) |name| {
1729 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{1716 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
1730 .name = arg["-needed-l".len..],1717 .name = name,
1731 .query = .{1718 .query = .{
1732 .needed = true,1719 .needed = true,
1733 .weak = false,1720 .weak = false,
...@@ -1736,9 +1723,9 @@ fn buildOutputType(...@@ -1736,9 +1723,9 @@ fn buildOutputType(
1736 .allow_so_scripts = allow_so_scripts,1723 .allow_so_scripts = allow_so_scripts,
1737 },1724 },
1738 } });1725 } });
1739 } else if (mem.startsWith(u8, arg, "-weak-l")) {1726 } else if (mem.cutPrefix(u8, arg, "-weak-l")) |name| {
1740 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{1727 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
1741 .name = arg["-weak-l".len..],1728 .name = name,
1742 .query = .{1729 .query = .{
1743 .needed = false,1730 .needed = false,
1744 .weak = true,1731 .weak = true,
...@@ -1749,13 +1736,10 @@ fn buildOutputType(...@@ -1749,13 +1736,10 @@ fn buildOutputType(
1749 } });1736 } });
1750 } else if (mem.startsWith(u8, arg, "-D")) {1737 } else if (mem.startsWith(u8, arg, "-D")) {
1751 try cc_argv.append(arena, arg);1738 try cc_argv.append(arena, arg);
1752 } else if (mem.startsWith(u8, arg, "-I")) {1739 } else if (mem.cutPrefix(u8, arg, "-I")) |rest| {
1753 try cssan.addIncludePath(arena, &cc_argv, .I, arg, arg[2..], true);1740 try cssan.addIncludePath(arena, &cc_argv, .I, arg, rest, true);
1754 } else if (mem.startsWith(u8, arg, "-x")) {1741 } else if (mem.cutPrefix(u8, arg, "-x")) |rest| {
1755 const lang = if (arg.len == "-x".len)1742 const lang = if (rest.len == 0) args_iter.nextOrFatal() else rest;
1756 args_iter.nextOrFatal()
1757 else
1758 arg["-x".len..];
1759 if (mem.eql(u8, lang, "none")) {1743 if (mem.eql(u8, lang, "none")) {
1760 file_ext = null;1744 file_ext = null;
1761 } else if (Compilation.LangToExt.get(lang)) |got_ext| {1745 } else if (Compilation.LangToExt.get(lang)) |got_ext| {
...@@ -1763,8 +1747,8 @@ fn buildOutputType(...@@ -1763,8 +1747,8 @@ fn buildOutputType(
1763 } else {1747 } else {
1764 fatal("language not recognized: '{s}'", .{lang});1748 fatal("language not recognized: '{s}'", .{lang});
1765 }1749 }
1766 } else if (mem.startsWith(u8, arg, "-mexec-model=")) {1750 } else if (mem.cutPrefix(u8, arg, "-mexec-model=")) |rest| {
1767 create_module.opts.wasi_exec_model = parseWasiExecModel(arg["-mexec-model=".len..]);1751 create_module.opts.wasi_exec_model = parseWasiExecModel(rest);
1768 } else if (mem.eql(u8, arg, "-municode")) {1752 } else if (mem.eql(u8, arg, "-municode")) {
1769 mingw_unicode_entry_point = true;1753 mingw_unicode_entry_point = true;
1770 } else {1754 } else {
...@@ -2442,8 +2426,8 @@ fn buildOutputType(...@@ -2442,8 +2426,8 @@ fn buildOutputType(
2442 linker_enable_new_dtags = false;2426 linker_enable_new_dtags = false;
2443 } else if (mem.eql(u8, arg, "-O")) {2427 } else if (mem.eql(u8, arg, "-O")) {
2444 linker_optimization = linker_args_it.nextOrFatal();2428 linker_optimization = linker_args_it.nextOrFatal();
2445 } else if (mem.startsWith(u8, arg, "-O")) {2429 } else if (mem.cutPrefix(u8, arg, "-O")) |rest| {
2446 linker_optimization = arg["-O".len..];2430 linker_optimization = rest;
2447 } else if (mem.eql(u8, arg, "-pagezero_size")) {2431 } else if (mem.eql(u8, arg, "-pagezero_size")) {
2448 const next_arg = linker_args_it.nextOrFatal();2432 const next_arg = linker_args_it.nextOrFatal();
2449 pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| {2433 pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| {
...@@ -2525,11 +2509,8 @@ fn buildOutputType(...@@ -2525,11 +2509,8 @@ fn buildOutputType(
2525 linker_compress_debug_sections = std.meta.stringToEnum(link.File.Lld.Elf.CompressDebugSections, arg1) orelse {2509 linker_compress_debug_sections = std.meta.stringToEnum(link.File.Lld.Elf.CompressDebugSections, arg1) orelse {
2526 fatal("expected [none|zlib|zstd] after --compress-debug-sections, found '{s}'", .{arg1});2510 fatal("expected [none|zlib|zstd] after --compress-debug-sections, found '{s}'", .{arg1});
2527 };2511 };
2528 } else if (mem.startsWith(u8, arg, "-z")) {2512 } else if (mem.cutPrefix(u8, arg, "-z")) |z_rest| {
2529 var z_arg = arg[2..];2513 const z_arg = if (z_rest.len == 0) linker_args_it.nextOrFatal() else z_rest;
2530 if (z_arg.len == 0) {
2531 z_arg = linker_args_it.nextOrFatal();
2532 }
2533 if (mem.eql(u8, z_arg, "nodelete")) {2514 if (mem.eql(u8, z_arg, "nodelete")) {
2534 linker_z_nodelete = true;2515 linker_z_nodelete = true;
2535 } else if (mem.eql(u8, z_arg, "notext")) {2516 } else if (mem.eql(u8, z_arg, "notext")) {
...@@ -2552,12 +2533,12 @@ fn buildOutputType(...@@ -2552,12 +2533,12 @@ fn buildOutputType(
2552 linker_z_relro = true;2533 linker_z_relro = true;
2553 } else if (mem.eql(u8, z_arg, "norelro")) {2534 } else if (mem.eql(u8, z_arg, "norelro")) {
2554 linker_z_relro = false;2535 linker_z_relro = false;
2555 } else if (mem.startsWith(u8, z_arg, "stack-size=")) {2536 } else if (mem.cutPrefix(u8, z_arg, "stack-size=")) |rest| {
2556 stack_size = parseStackSize(z_arg["stack-size=".len..]);2537 stack_size = parseStackSize(rest);
2557 } else if (mem.startsWith(u8, z_arg, "common-page-size=")) {2538 } else if (prefixedIntArg(z_arg, "common-page-size=")) |int| {
2558 linker_z_common_page_size = parseIntSuffix(z_arg, "common-page-size=".len);2539 linker_z_common_page_size = int;
2559 } else if (mem.startsWith(u8, z_arg, "max-page-size=")) {2540 } else if (prefixedIntArg(z_arg, "max-page-size=")) |int| {
2560 linker_z_max_page_size = parseIntSuffix(z_arg, "max-page-size=".len);2541 linker_z_max_page_size = int;
2561 } else {2542 } else {
2562 fatal("unsupported linker extension flag: -z {s}", .{z_arg});2543 fatal("unsupported linker extension flag: -z {s}", .{z_arg});
2563 }2544 }
...@@ -2671,9 +2652,9 @@ fn buildOutputType(...@@ -2671,9 +2652,9 @@ fn buildOutputType(
2671 .allow_so_scripts = allow_so_scripts,2652 .allow_so_scripts = allow_so_scripts,
2672 },2653 },
2673 } });2654 } });
2674 } else if (mem.startsWith(u8, arg, "-weak-l")) {2655 } else if (mem.cutPrefix(u8, arg, "-weak-l")) |rest| {
2675 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{2656 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
2676 .name = arg["-weak-l".len..],2657 .name = rest,
2677 .query = .{2658 .query = .{
2678 .weak = true,2659 .weak = true,
2679 .needed = false,2660 .needed = false,
...@@ -3768,8 +3749,7 @@ fn createModule(...@@ -3768,8 +3749,7 @@ fn createModule(
3768 try mcpu_buffer.appendSlice(cli_mod.target_mcpu orelse "baseline");3749 try mcpu_buffer.appendSlice(cli_mod.target_mcpu orelse "baseline");
37693750
3770 for (create_module.llvm_m_args.items) |llvm_m_arg| {3751 for (create_module.llvm_m_args.items) |llvm_m_arg| {
3771 if (mem.startsWith(u8, llvm_m_arg, "mno-")) {3752 if (mem.cutPrefix(u8, llvm_m_arg, "mno-")) |llvm_name| {
3772 const llvm_name = llvm_m_arg["mno-".len..];
3773 const zig_name = llvm_to_zig_name.get(llvm_name) orelse {3753 const zig_name = llvm_to_zig_name.get(llvm_name) orelse {
3774 fatal("target architecture {s} has no LLVM CPU feature named '{s}'", .{3754 fatal("target architecture {s} has no LLVM CPU feature named '{s}'", .{
3775 @tagName(cpu_arch), llvm_name,3755 @tagName(cpu_arch), llvm_name,
...@@ -3777,8 +3757,7 @@ fn createModule(...@@ -3777,8 +3757,7 @@ fn createModule(
3777 };3757 };
3778 try mcpu_buffer.append('-');3758 try mcpu_buffer.append('-');
3779 try mcpu_buffer.appendSlice(zig_name);3759 try mcpu_buffer.appendSlice(zig_name);
3780 } else if (mem.startsWith(u8, llvm_m_arg, "m")) {3760 } else if (mem.cutPrefix(u8, llvm_m_arg, "m")) |llvm_name| {
3781 const llvm_name = llvm_m_arg["m".len..];
3782 const zig_name = llvm_to_zig_name.get(llvm_name) orelse {3761 const zig_name = llvm_to_zig_name.get(llvm_name) orelse {
3783 fatal("target architecture {s} has no LLVM CPU feature named '{s}'", .{3762 fatal("target architecture {s} has no LLVM CPU feature named '{s}'", .{
3784 @tagName(cpu_arch), llvm_name,3763 @tagName(cpu_arch), llvm_name,
...@@ -4850,9 +4829,8 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -4850,9 +4829,8 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
4850 reference_trace = 256;4829 reference_trace = 256;
4851 } else if (mem.eql(u8, arg, "--fetch")) {4830 } else if (mem.eql(u8, arg, "--fetch")) {
4852 fetch_only = true;4831 fetch_only = true;
4853 } else if (mem.startsWith(u8, arg, "--fetch=")) {4832 } else if (mem.cutPrefix(u8, arg, "--fetch=")) |sub_arg| {
4854 fetch_only = true;4833 fetch_only = true;
4855 const sub_arg = arg["--fetch=".len..];
4856 fetch_mode = std.meta.stringToEnum(Package.Fetch.JobQueue.Mode, sub_arg) orelse4834 fetch_mode = std.meta.stringToEnum(Package.Fetch.JobQueue.Mode, sub_arg) orelse
4857 fatal("expected [needed|all] after '--fetch=', found '{s}'", .{4835 fatal("expected [needed|all] after '--fetch=', found '{s}'", .{
4858 sub_arg,4836 sub_arg,
...@@ -4863,8 +4841,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -4863,8 +4841,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
4863 system_pkg_dir_path = args[i];4841 system_pkg_dir_path = args[i];
4864 try child_argv.append("--system");4842 try child_argv.append("--system");
4865 continue;4843 continue;
4866 } else if (mem.startsWith(u8, arg, "-freference-trace=")) {4844 } else if (mem.cutPrefix(u8, arg, "-freference-trace=")) |num| {
4867 const num = arg["-freference-trace=".len..];
4868 reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {4845 reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
4869 fatal("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) });4846 fatal("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) });
4870 };4847 };
...@@ -4914,10 +4891,10 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -4914,10 +4891,10 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
4914 verbose_generic_instances = true;4891 verbose_generic_instances = true;
4915 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {4892 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
4916 verbose_llvm_ir = "-";4893 verbose_llvm_ir = "-";
4917 } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) {4894 } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-ir=")) |rest| {
4918 verbose_llvm_ir = arg["--verbose-llvm-ir=".len..];4895 verbose_llvm_ir = rest;
4919 } else if (mem.startsWith(u8, arg, "--verbose-llvm-bc=")) {4896 } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-bc=")) |rest| {
4920 verbose_llvm_bc = arg["--verbose-llvm-bc=".len..];4897 verbose_llvm_bc = rest;
4921 } else if (mem.eql(u8, arg, "--verbose-cimport")) {4898 } else if (mem.eql(u8, arg, "--verbose-cimport")) {
4922 verbose_cimport = true;4899 verbose_cimport = true;
4923 } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {4900 } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {
...@@ -4930,8 +4907,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -4930,8 +4907,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
4930 };4907 };
4931 try child_argv.appendSlice(&.{ arg, args[i] });4908 try child_argv.appendSlice(&.{ arg, args[i] });
4932 continue;4909 continue;
4933 } else if (mem.startsWith(u8, arg, "-j")) {4910 } else if (mem.cutPrefix(u8, arg, "-j")) |str| {
4934 const str = arg["-j".len..];
4935 const num = std.fmt.parseUnsigned(u32, str, 10) catch |err| {4911 const num = std.fmt.parseUnsigned(u32, str, 10) catch |err| {
4936 fatal("unable to parse jobs count '{s}': {s}", .{4912 fatal("unable to parse jobs count '{s}': {s}", .{
4937 str, @errorName(err),4913 str, @errorName(err),
...@@ -6507,10 +6483,9 @@ fn eatIntPrefix(arg: []const u8, base: u8) []const u8 {...@@ -6507,10 +6483,9 @@ fn eatIntPrefix(arg: []const u8, base: u8) []const u8 {
6507 return arg;6483 return arg;
6508}6484}
65096485
6510fn parseIntSuffix(arg: []const u8, prefix_len: usize) u64 {6486fn prefixedIntArg(arg: []const u8, prefix: []const u8) ?u64 {
6511 return std.fmt.parseUnsigned(u64, arg[prefix_len..], 0) catch |err| {6487 const number = mem.cutPrefix(u8, arg, prefix) orelse return null;
6512 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });6488 return std.fmt.parseUnsigned(u64, number, 0) catch |err| fatal("unable to parse '{s}': {t}", .{ arg, err });
6513 };
6514}6489}
65156490
6516fn warnAboutForeignBinaries(6491fn warnAboutForeignBinaries(
...@@ -6837,12 +6812,12 @@ fn cmdFetch(...@@ -6837,12 +6812,12 @@ fn cmdFetch(
6837 debug_hash = true;6812 debug_hash = true;
6838 } else if (mem.eql(u8, arg, "--save")) {6813 } else if (mem.eql(u8, arg, "--save")) {
6839 save = .{ .yes = null };6814 save = .{ .yes = null };
6840 } else if (mem.startsWith(u8, arg, "--save=")) {6815 } else if (mem.cutPrefix(u8, arg, "--save=")) |rest| {
6841 save = .{ .yes = arg["--save=".len..] };6816 save = .{ .yes = rest };
6842 } else if (mem.eql(u8, arg, "--save-exact")) {6817 } else if (mem.eql(u8, arg, "--save-exact")) {
6843 save = .{ .exact = null };6818 save = .{ .exact = null };
6844 } else if (mem.startsWith(u8, arg, "--save-exact=")) {6819 } else if (mem.cutPrefix(u8, arg, "--save-exact=")) |rest| {
6845 save = .{ .exact = arg["--save-exact=".len..] };6820 save = .{ .exact = rest };
6846 } else {6821 } else {
6847 fatal("unrecognized parameter: '{s}'", .{arg});6822 fatal("unrecognized parameter: '{s}'", .{arg});
6848 }6823 }